0527 sync
This commit is contained in:
parent
23bbfc4b63
commit
92da6c71ce
|
@ -55,8 +55,8 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "anyComponentStyle",
|
"type": "anyComponentStyle",
|
||||||
"maximumWarning": "6kb",
|
"maximumWarning": "30kb",
|
||||||
"maximumError": "10kb"
|
"maximumError": "50kb"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -86,8 +86,8 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "anyComponentStyle",
|
"type": "anyComponentStyle",
|
||||||
"maximumWarning": "6kb",
|
"maximumWarning": "30kb",
|
||||||
"maximumError": "10kb"
|
"maximumError": "50kb"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
18
package.json
18
package.json
|
@ -32,12 +32,12 @@
|
||||||
"@ngrx/router-store": "^9.0.0",
|
"@ngrx/router-store": "^9.0.0",
|
||||||
"@ngrx/store": "^9.0.0",
|
"@ngrx/store": "^9.0.0",
|
||||||
"@ucap/api": "~0.0.2",
|
"@ucap/api": "~0.0.2",
|
||||||
"@ucap/api-common": "~0.0.3",
|
"@ucap/api-common": "~0.0.5",
|
||||||
"@ucap/api-external": "~0.0.5",
|
"@ucap/api-external": "~0.0.5",
|
||||||
"@ucap/api-message": "~0.0.3",
|
"@ucap/api-message": "~0.0.3",
|
||||||
"@ucap/api-prompt": "~0.0.3",
|
"@ucap/api-prompt": "~0.0.3",
|
||||||
"@ucap/api-public": "~0.0.4",
|
"@ucap/api-public": "~0.0.4",
|
||||||
"@ucap/core": "~0.0.7",
|
"@ucap/core": "~0.0.10",
|
||||||
"@ucap/logger": "~0.0.12",
|
"@ucap/logger": "~0.0.12",
|
||||||
"@ucap/native": "~0.0.6",
|
"@ucap/native": "~0.0.6",
|
||||||
"@ucap/native-browser": "~0.0.5",
|
"@ucap/native-browser": "~0.0.5",
|
||||||
|
@ -46,7 +46,7 @@
|
||||||
"@ucap/ng-api-message": "~0.0.1",
|
"@ucap/ng-api-message": "~0.0.1",
|
||||||
"@ucap/ng-api-prompt": "~0.0.1",
|
"@ucap/ng-api-prompt": "~0.0.1",
|
||||||
"@ucap/ng-api-public": "~0.0.1",
|
"@ucap/ng-api-public": "~0.0.1",
|
||||||
"@ucap/ng-core": "~0.0.1",
|
"@ucap/ng-core": "~0.0.7",
|
||||||
"@ucap/ng-logger": "~0.0.2",
|
"@ucap/ng-logger": "~0.0.2",
|
||||||
"@ucap/ng-i18n": "~0.0.6",
|
"@ucap/ng-i18n": "~0.0.6",
|
||||||
"@ucap/ng-native": "~0.0.1",
|
"@ucap/ng-native": "~0.0.1",
|
||||||
|
@ -69,16 +69,16 @@
|
||||||
"@ucap/ng-protocol-sync": "~0.0.3",
|
"@ucap/ng-protocol-sync": "~0.0.3",
|
||||||
"@ucap/ng-protocol-umg": "~0.0.3",
|
"@ucap/ng-protocol-umg": "~0.0.3",
|
||||||
"@ucap/ng-store-authentication": "~0.0.11",
|
"@ucap/ng-store-authentication": "~0.0.11",
|
||||||
"@ucap/ng-store-chat": "~0.0.13",
|
"@ucap/ng-store-chat": "~0.0.16",
|
||||||
"@ucap/ng-store-group": "~0.0.14",
|
"@ucap/ng-store-group": "~0.0.14",
|
||||||
"@ucap/ng-store-organization": "~0.0.8",
|
"@ucap/ng-store-organization": "~0.0.8",
|
||||||
"@ucap/ng-web-socket": "~0.0.2",
|
"@ucap/ng-web-socket": "~0.0.2",
|
||||||
"@ucap/ng-web-storage": "~0.0.3",
|
"@ucap/ng-web-storage": "~0.0.3",
|
||||||
"@ucap/ng-ui": "~0.0.19",
|
"@ucap/ng-ui": "~0.0.19",
|
||||||
"@ucap/ng-ui-organization": "~0.0.55",
|
"@ucap/ng-ui-organization": "~0.0.83",
|
||||||
"@ucap/ng-ui-authentication": "~0.0.24",
|
"@ucap/ng-ui-authentication": "~0.0.25",
|
||||||
"@ucap/ng-ui-group": "~0.0.33",
|
"@ucap/ng-ui-group": "~0.0.33",
|
||||||
"@ucap/ng-ui-chat": "~0.0.9",
|
"@ucap/ng-ui-chat": "~0.0.12",
|
||||||
"@ucap/ng-ui-material": "~0.0.4",
|
"@ucap/ng-ui-material": "~0.0.4",
|
||||||
"@ucap/ng-ui-skin-default": "~0.0.1",
|
"@ucap/ng-ui-skin-default": "~0.0.1",
|
||||||
"@ucap/pi": "~0.0.5",
|
"@ucap/pi": "~0.0.5",
|
||||||
|
@ -93,12 +93,12 @@
|
||||||
"@ucap/protocol-option": "~0.0.7",
|
"@ucap/protocol-option": "~0.0.7",
|
||||||
"@ucap/protocol-ping": "~0.0.6",
|
"@ucap/protocol-ping": "~0.0.6",
|
||||||
"@ucap/protocol-query": "~0.0.5",
|
"@ucap/protocol-query": "~0.0.5",
|
||||||
"@ucap/protocol-room": "~0.0.5",
|
"@ucap/protocol-room": "~0.0.6",
|
||||||
"@ucap/protocol-service": "~0.0.4",
|
"@ucap/protocol-service": "~0.0.4",
|
||||||
"@ucap/protocol-status": "~0.0.5",
|
"@ucap/protocol-status": "~0.0.5",
|
||||||
"@ucap/protocol-sync": "~0.0.4",
|
"@ucap/protocol-sync": "~0.0.4",
|
||||||
"@ucap/protocol-umg": "~0.0.5",
|
"@ucap/protocol-umg": "~0.0.5",
|
||||||
"@ucap/ui-scss": "~0.0.4",
|
"@ucap/ui-scss": "~0.0.5",
|
||||||
"@ucap/web-socket": "~0.0.10",
|
"@ucap/web-socket": "~0.0.10",
|
||||||
"@ucap/web-storage": "~0.0.9",
|
"@ucap/web-storage": "~0.0.9",
|
||||||
"autolinker": "^3.13.0",
|
"autolinker": "^3.13.0",
|
||||||
|
|
|
@ -15,6 +15,7 @@ import { AppAuthenticationService } from './services/app-authentication.service'
|
||||||
import { AppNativeService } from './services/app-native.service';
|
import { AppNativeService } from './services/app-native.service';
|
||||||
import { AppService } from './services/app.service';
|
import { AppService } from './services/app.service';
|
||||||
import { AppChatService } from './services/app-chat.service';
|
import { AppChatService } from './services/app-chat.service';
|
||||||
|
import { AppFileService } from './services/app-file.service';
|
||||||
|
|
||||||
const GUARDS = [AppAuthenticationGuard];
|
const GUARDS = [AppAuthenticationGuard];
|
||||||
const RESOLVERS = [AppSessionResolver];
|
const RESOLVERS = [AppSessionResolver];
|
||||||
|
@ -22,6 +23,7 @@ const SERVICES = [
|
||||||
AppService,
|
AppService,
|
||||||
AppAuthenticationService,
|
AppAuthenticationService,
|
||||||
AppNativeService,
|
AppNativeService,
|
||||||
|
AppFileService,
|
||||||
AppChatService
|
AppChatService
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -22,11 +22,11 @@ $typography: mat-typography-config(
|
||||||
// Define the palettes for your theme using the Material Design palettes available in palette.scss
|
// Define the palettes for your theme using the Material Design palettes available in palette.scss
|
||||||
// (imported above). For each palette, you can optionally specify a default, lighter, and darker
|
// (imported above). For each palette, you can optionally specify a default, lighter, and darker
|
||||||
// hue. Available color palettes: https://material.io/design/color/
|
// hue. Available color palettes: https://material.io/design/color/
|
||||||
$lgRed-app-primary: mat-palette($lg-red);
|
$lgRed-app-primary: mat-palette($ucap-color-primary);
|
||||||
$lgRed-app-accent: mat-palette($lg-red, A200, A100, A400);
|
$lgRed-app-accent: mat-palette($ucap-color-accent, 700);
|
||||||
|
|
||||||
// The warn palette is optional (defaults to red).
|
// The warn palette is optional (defaults to red).
|
||||||
$lgRed-app-warn: mat-palette($lg-red);
|
$lgRed-app-warn: mat-palette($ucap-color-warn, 500);
|
||||||
|
|
||||||
// Create the theme object (a Sass map containing all of the palettes).
|
// Create the theme object (a Sass map containing all of the palettes).
|
||||||
$lgRed-app-theme: mat-light-theme(
|
$lgRed-app-theme: mat-light-theme(
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { MatSidenav } from '@angular/material/sidenav';
|
||||||
import { LogService } from '@ucap/ng-logger';
|
import { LogService } from '@ucap/ng-logger';
|
||||||
|
|
||||||
import { AppSelector } from '@app/store/state';
|
import { AppSelector } from '@app/store/state';
|
||||||
|
import { AppChatService } from '@app/services/app-chat.service';
|
||||||
|
|
||||||
const NAVS = ['group', 'chat', 'organization', 'message'];
|
const NAVS = ['group', 'chat', 'organization', 'message'];
|
||||||
|
|
||||||
|
@ -37,6 +38,7 @@ export class DefaultLayoutComponent implements OnInit, OnDestroy {
|
||||||
constructor(
|
constructor(
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private store: Store<any>,
|
private store: Store<any>,
|
||||||
|
private appChatService: AppChatService,
|
||||||
private logService: LogService
|
private logService: LogService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
@ -175,7 +177,7 @@ export class DefaultLayoutComponent implements OnInit, OnDestroy {
|
||||||
break;
|
break;
|
||||||
case 'CAHT_NEW_ADD':
|
case 'CAHT_NEW_ADD':
|
||||||
{
|
{
|
||||||
this.logService.debug('CAHT_NEW_ADD');
|
this.appChatService.newOpenRoomDialog();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'CHAT_NEW_TIMER_ADD':
|
case 'CHAT_NEW_TIMER_ADD':
|
||||||
|
|
|
@ -17,6 +17,9 @@ import { UiModule } from '@ucap/ng-ui';
|
||||||
|
|
||||||
import { COMPONENTS } from './components';
|
import { COMPONENTS } from './components';
|
||||||
import { DIALOGS } from './dialogs';
|
import { DIALOGS } from './dialogs';
|
||||||
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { I18nModule, UCAP_I18N_NAMESPACE } from '@ucap/ng-i18n';
|
||||||
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -30,13 +33,21 @@ import { DIALOGS } from './dialogs';
|
||||||
MatSidenavModule,
|
MatSidenavModule,
|
||||||
MatTabsModule,
|
MatTabsModule,
|
||||||
MatToolbarModule,
|
MatToolbarModule,
|
||||||
|
MatSelectModule,
|
||||||
|
|
||||||
PerfectScrollbarModule,
|
PerfectScrollbarModule,
|
||||||
|
|
||||||
|
I18nModule,
|
||||||
UiModule
|
UiModule
|
||||||
],
|
],
|
||||||
exports: [...COMPONENTS, ...DIALOGS],
|
exports: [...COMPONENTS, ...DIALOGS],
|
||||||
declarations: [...COMPONENTS, ...DIALOGS],
|
declarations: [...COMPONENTS, ...DIALOGS],
|
||||||
entryComponents: [...DIALOGS]
|
entryComponents: [...DIALOGS],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: UCAP_I18N_NAMESPACE,
|
||||||
|
useValue: ['chat', 'common']
|
||||||
|
}
|
||||||
|
]
|
||||||
})
|
})
|
||||||
export class AppLayoutsModule {}
|
export class AppLayoutsModule {}
|
||||||
|
|
|
@ -7,9 +7,11 @@ $login-bg-h: 100/1080;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
// box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
// display: flex;
|
display: flex;
|
||||||
// flex-direction: column;
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
background-color: $bg-gray;
|
background-color: $bg-gray;
|
||||||
background-image: url(../../../../assets/images/bg/bg_login_circle_square01.svg),
|
background-image: url(../../../../assets/images/bg/bg_login_circle_square01.svg),
|
||||||
|
|
|
@ -15,6 +15,7 @@ import { AppChatRoutingPageModule } from './chat-routing.page.module';
|
||||||
|
|
||||||
import { UiModule } from '@ucap/ng-ui';
|
import { UiModule } from '@ucap/ng-ui';
|
||||||
import { COMPONENTS } from './components';
|
import { COMPONENTS } from './components';
|
||||||
|
import { UCAP_I18N_NAMESPACE, I18nModule } from '@ucap/ng-i18n';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -30,9 +31,16 @@ import { COMPONENTS } from './components';
|
||||||
AppChatSectionModule,
|
AppChatSectionModule,
|
||||||
AppChatRoutingPageModule,
|
AppChatRoutingPageModule,
|
||||||
|
|
||||||
|
I18nModule,
|
||||||
UiModule
|
UiModule
|
||||||
],
|
],
|
||||||
declarations: [...COMPONENTS],
|
declarations: [...COMPONENTS],
|
||||||
entryComponents: []
|
entryComponents: [],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: UCAP_I18N_NAMESPACE,
|
||||||
|
useValue: ['chat', 'common']
|
||||||
|
}
|
||||||
|
]
|
||||||
})
|
})
|
||||||
export class AppChatPageModule {}
|
export class AppChatPageModule {}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<div fxFlexFill class="sidenav-container">
|
<div fxFlexFill class="sidenav-container">
|
||||||
<div class="chat-header">
|
<div class="chat-header">
|
||||||
<h3>대화</h3>
|
<h3>{{ 'label.chat' | ucapI18n }}</h3>
|
||||||
<div class="chat-menu-btn">
|
<div class="chat-menu-btn">
|
||||||
<button
|
<button
|
||||||
mat-icon-button
|
mat-icon-button
|
||||||
|
|
|
@ -44,6 +44,9 @@ export class SidenavPageComponent implements OnInit, OnDestroy {
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.ngOnDestroySubject = new Subject<boolean>();
|
this.ngOnDestroySubject = new Subject<boolean>();
|
||||||
|
|
||||||
|
// language setting
|
||||||
|
this.i18nService.setDefaultNamespace('chat');
|
||||||
|
|
||||||
this.store
|
this.store
|
||||||
.pipe(takeUntil(this.ngOnDestroySubject), select(RoomSelector.rooms))
|
.pipe(takeUntil(this.ngOnDestroySubject), select(RoomSelector.rooms))
|
||||||
.subscribe((rooms) => {
|
.subscribe((rooms) => {
|
||||||
|
@ -67,8 +70,8 @@ export class SidenavPageComponent implements OnInit, OnDestroy {
|
||||||
ConfirmDialogResult
|
ConfirmDialogResult
|
||||||
>(ConfirmDialogComponent, {
|
>(ConfirmDialogComponent, {
|
||||||
data: {
|
data: {
|
||||||
title: this.i18nService.t('room.dialog.titleExitFromRoom'),
|
title: this.i18nService.t('dialog.title.exitFromRoom'),
|
||||||
html: this.i18nService.t('room.dialog.confirmExitFromRoom')
|
html: this.i18nService.t('dialog.confirmExitFromRoom')
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="extra-box" fxFlex="0 0 50px">
|
<div class="extra-box" fxFlex="0 0 50px">
|
||||||
<app-organization-search-for-tenant (changed)="onKeyDownSearch($event)">
|
<app-organization-search-for-tenant [(searchData)]="companySearchData">
|
||||||
</app-organization-search-for-tenant>
|
</app-organization-search-for-tenant>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@
|
||||||
<app-sections-group-list
|
<app-sections-group-list
|
||||||
#sectionGroupList
|
#sectionGroupList
|
||||||
fxFlexFill
|
fxFlexFill
|
||||||
[searchObj]="searchObj"
|
[searchData]="companySearchData"
|
||||||
[showType]="showType"
|
[showType]="showType"
|
||||||
></app-sections-group-list>
|
></app-sections-group-list>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Subscription, of } from 'rxjs';
|
import { of, Subject } from 'rxjs';
|
||||||
import { take, map, catchError } from 'rxjs/operators';
|
import { take, map, catchError, takeUntil } from 'rxjs/operators';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Component,
|
Component,
|
||||||
|
@ -14,14 +14,14 @@ import { Store } from '@ngrx/store';
|
||||||
|
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
|
|
||||||
|
import { ParamsUtil } from '@ucap/ng-core';
|
||||||
import { LogService } from '@ucap/ng-logger';
|
import { LogService } from '@ucap/ng-logger';
|
||||||
import { GroupActions } from '@ucap/ng-store-group';
|
import { I18nService } from '@ucap/ng-i18n';
|
||||||
|
|
||||||
import { SelectUserDialogType } from '@app/types';
|
|
||||||
|
|
||||||
import { CreateDialogComponent } from '@app/sections/group/dialogs/create.dialog.component';
|
import { CreateDialogComponent } from '@app/sections/group/dialogs/create.dialog.component';
|
||||||
import { I18nService } from '@ucap/ng-i18n';
|
|
||||||
import { ListSectionComponent } from '@app/sections/group/components/list.section.component';
|
import { ListSectionComponent } from '@app/sections/group/components/list.section.component';
|
||||||
|
import { SearchData } from '@app/ucap/organization/models/search-data';
|
||||||
|
import { QueryParams } from '@app/pages/organization/types/params.type';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-pages-group-sidenav',
|
selector: 'app-pages-group-sidenav',
|
||||||
|
@ -32,14 +32,19 @@ export class SidenavPageComponent implements OnInit, OnDestroy {
|
||||||
@ViewChild('sectionGroupList', { static: false })
|
@ViewChild('sectionGroupList', { static: false })
|
||||||
sectionGroupList: ListSectionComponent;
|
sectionGroupList: ListSectionComponent;
|
||||||
|
|
||||||
searchObj: any = {
|
set companySearchData(searchData: SearchData) {
|
||||||
isShowSearch: false,
|
this._companySearchData = searchData;
|
||||||
companyCode: '',
|
}
|
||||||
searchWord: ''
|
get companySearchData() {
|
||||||
};
|
return this._companySearchData;
|
||||||
|
}
|
||||||
|
// tslint:disable-next-line: variable-name
|
||||||
|
_companySearchData: SearchData;
|
||||||
|
|
||||||
showType: string;
|
showType: string;
|
||||||
|
|
||||||
|
private ngOnDestroySubject: Subject<boolean>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private activatedRoute: ActivatedRoute,
|
private activatedRoute: ActivatedRoute,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
|
@ -53,33 +58,14 @@ export class SidenavPageComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
this.ngOnDestroySubject = new Subject<boolean>();
|
||||||
|
|
||||||
this.showType = 'ALL';
|
this.showType = 'ALL';
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {}
|
ngOnDestroy(): void {}
|
||||||
|
|
||||||
onClickFab(event: MouseEvent) {}
|
onClickFab(event: MouseEvent) {}
|
||||||
onKeyDownSearch(params: {
|
|
||||||
isShowSearch: boolean;
|
|
||||||
companyCode: string;
|
|
||||||
searchWord: string;
|
|
||||||
}) {
|
|
||||||
this.searchObj = {
|
|
||||||
isShowSearch: params.isShowSearch,
|
|
||||||
companyCode: params.companyCode,
|
|
||||||
searchWord: params.searchWord
|
|
||||||
};
|
|
||||||
this.changeDetectorRef.detectChanges();
|
|
||||||
}
|
|
||||||
|
|
||||||
onClickCancel() {
|
|
||||||
this.searchObj = {
|
|
||||||
isShowSearch: false,
|
|
||||||
companyCode: '',
|
|
||||||
searchWord: ''
|
|
||||||
};
|
|
||||||
this.changeDetectorRef.detectChanges();
|
|
||||||
}
|
|
||||||
|
|
||||||
onClickGroupMenu(menuType: string) {
|
onClickGroupMenu(menuType: string) {
|
||||||
switch (menuType) {
|
switch (menuType) {
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
<div fxFlexFill>
|
<div class="index-page-container" fxLayout="column">
|
||||||
<app-sections-organization-member-list
|
<!-- search start-->
|
||||||
[searchData]="_searchData"
|
<div fxFlex="0 0 50px">
|
||||||
></app-sections-organization-member-list>
|
<app-organization-search-for-tenant [(searchData)]="companySearchData">
|
||||||
|
</app-organization-search-for-tenant>
|
||||||
|
</div>
|
||||||
|
<!-- search end-->
|
||||||
|
<div class="member-list-body" fxFlex="1 1 auto">
|
||||||
|
<app-sections-organization-member-list [searchData]="deptSearchData">
|
||||||
|
</app-sections-organization-member-list>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
.index-page-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
|
@ -2,10 +2,14 @@ import { Subject } from 'rxjs';
|
||||||
import { takeUntil } from 'rxjs/operators';
|
import { takeUntil } from 'rxjs/operators';
|
||||||
|
|
||||||
import { Component, OnInit, OnDestroy, ChangeDetectorRef } from '@angular/core';
|
import { Component, OnInit, OnDestroy, ChangeDetectorRef } from '@angular/core';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute, Router, Params } from '@angular/router';
|
||||||
|
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
|
|
||||||
|
import { ParamsUtil } from '@ucap/ng-core';
|
||||||
|
|
||||||
|
import { SearchData } from '@app/ucap/organization/models/search-data';
|
||||||
|
|
||||||
import { QueryParams } from '../types/params.type';
|
import { QueryParams } from '../types/params.type';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -14,12 +18,17 @@ import { QueryParams } from '../types/params.type';
|
||||||
styleUrls: ['./index.page.component.scss']
|
styleUrls: ['./index.page.component.scss']
|
||||||
})
|
})
|
||||||
export class IndexPageComponent implements OnInit, OnDestroy {
|
export class IndexPageComponent implements OnInit, OnDestroy {
|
||||||
|
set companySearchData(searchData: SearchData) {
|
||||||
|
this._companySearchData = searchData;
|
||||||
|
this.onChangedCompanySearch();
|
||||||
|
}
|
||||||
|
get companySearchData() {
|
||||||
|
return this._companySearchData;
|
||||||
|
}
|
||||||
// tslint:disable-next-line: variable-name
|
// tslint:disable-next-line: variable-name
|
||||||
_searchData: {
|
_companySearchData: SearchData;
|
||||||
companyCode: string;
|
|
||||||
searchWord: string;
|
deptSearchData: SearchData;
|
||||||
isSearch: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
deptSeq: string;
|
deptSeq: string;
|
||||||
|
|
||||||
|
@ -27,6 +36,7 @@ export class IndexPageComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private store: Store<any>,
|
private store: Store<any>,
|
||||||
|
private router: Router,
|
||||||
private activatedRoute: ActivatedRoute,
|
private activatedRoute: ActivatedRoute,
|
||||||
private changeDetectorRef: ChangeDetectorRef
|
private changeDetectorRef: ChangeDetectorRef
|
||||||
) {}
|
) {}
|
||||||
|
@ -37,14 +47,25 @@ export class IndexPageComponent implements OnInit, OnDestroy {
|
||||||
this.activatedRoute.queryParams
|
this.activatedRoute.queryParams
|
||||||
.pipe(takeUntil(this.ngOnDestroySubject))
|
.pipe(takeUntil(this.ngOnDestroySubject))
|
||||||
.subscribe((params) => {
|
.subscribe((params) => {
|
||||||
console.log('activatedRoute.queryParams');
|
|
||||||
if (!!params) {
|
if (!!params) {
|
||||||
const companyCode = params[QueryParams.DEPT_SEQ];
|
const deptSeq = params[QueryParams.DEPT_SEQ];
|
||||||
console.log('activatedRoute.queryParams', companyCode);
|
const companyCode = params[QueryParams.COMPANY_CODE];
|
||||||
this._searchData = {
|
const searchWord = params[QueryParams.SEARCH_WORD];
|
||||||
companyCode,
|
const bySearch = ParamsUtil.getParameter<boolean>(
|
||||||
searchWord: '',
|
params,
|
||||||
isSearch: false
|
QueryParams.BY_SEARCH,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
this.deptSearchData = {
|
||||||
|
deptSeq: bySearch ? undefined : deptSeq,
|
||||||
|
companyCode: bySearch ? companyCode : undefined,
|
||||||
|
searchWord: bySearch ? searchWord : undefined,
|
||||||
|
bySearch
|
||||||
|
};
|
||||||
|
|
||||||
|
this._companySearchData = {
|
||||||
|
...this.deptSearchData
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -55,4 +76,23 @@ export class IndexPageComponent implements OnInit, OnDestroy {
|
||||||
this.ngOnDestroySubject.complete();
|
this.ngOnDestroySubject.complete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onChangedCompanySearch() {
|
||||||
|
const queryParams: Params = {};
|
||||||
|
queryParams[QueryParams.COMPANY_CODE] = this._companySearchData.companyCode;
|
||||||
|
queryParams[QueryParams.SEARCH_WORD] = this._companySearchData.searchWord;
|
||||||
|
queryParams[QueryParams.BY_SEARCH] = String(true);
|
||||||
|
|
||||||
|
this.router.navigate(
|
||||||
|
[
|
||||||
|
'organization',
|
||||||
|
{
|
||||||
|
outlets: { content: 'index' }
|
||||||
|
}
|
||||||
|
],
|
||||||
|
{
|
||||||
|
queryParams
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,7 @@ export class SidenavPageComponent implements OnInit, OnDestroy {
|
||||||
onClickedTree(node: DeptInfo) {
|
onClickedTree(node: DeptInfo) {
|
||||||
const queryParams: Params = {};
|
const queryParams: Params = {};
|
||||||
queryParams[QueryParams.DEPT_SEQ] = String(node.seq);
|
queryParams[QueryParams.DEPT_SEQ] = String(node.seq);
|
||||||
|
queryParams[QueryParams.BY_SEARCH] = String(false);
|
||||||
|
|
||||||
this.router.navigate(
|
this.router.navigate(
|
||||||
[
|
[
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
export enum QueryParams {
|
export enum QueryParams {
|
||||||
DEPT_SEQ = 'dept_seq'
|
DEPT_SEQ = 'dept_seq',
|
||||||
|
COMPANY_CODE = 'company_code',
|
||||||
|
SEARCH_WORD = 'search_word',
|
||||||
|
BY_SEARCH = 'by_search'
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { ReactiveFormsModule } from '@angular/forms';
|
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
|
||||||
|
|
||||||
import { FlexLayoutModule } from '@angular/flex-layout';
|
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ import { MatSelectModule } from '@angular/material/select';
|
||||||
import { MatTreeModule } from '@angular/material/tree';
|
import { MatTreeModule } from '@angular/material/tree';
|
||||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||||
|
import { MatStepperModule } from '@angular/material/stepper';
|
||||||
|
|
||||||
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
|
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
|
||||||
|
|
||||||
|
@ -27,12 +28,16 @@ import { I18nModule, UCAP_I18N_NAMESPACE } from '@ucap/ng-i18n';
|
||||||
import { UiModule } from '@ucap/ng-ui';
|
import { UiModule } from '@ucap/ng-ui';
|
||||||
import { ChatUiModule } from '@ucap/ng-ui-chat';
|
import { ChatUiModule } from '@ucap/ng-ui-chat';
|
||||||
import { AppChatModule } from '@app/ucap/chat/chat.module';
|
import { AppChatModule } from '@app/ucap/chat/chat.module';
|
||||||
|
import { AppLayoutsModule } from '@app/layouts/layouts.module';
|
||||||
|
import { AppGroupSectionModule } from '../group/group.section.module';
|
||||||
|
|
||||||
import { COMPONENTS } from './components';
|
import { COMPONENTS } from './components';
|
||||||
|
import { DIALOGS } from './dialogs';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
|
FormsModule,
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
FlexLayoutModule,
|
FlexLayoutModule,
|
||||||
|
|
||||||
|
@ -50,6 +55,7 @@ import { COMPONENTS } from './components';
|
||||||
MatRippleModule,
|
MatRippleModule,
|
||||||
MatTreeModule,
|
MatTreeModule,
|
||||||
MatTooltipModule,
|
MatTooltipModule,
|
||||||
|
MatStepperModule,
|
||||||
|
|
||||||
PerfectScrollbarModule,
|
PerfectScrollbarModule,
|
||||||
ScrollingModule,
|
ScrollingModule,
|
||||||
|
@ -57,12 +63,14 @@ import { COMPONENTS } from './components';
|
||||||
I18nModule,
|
I18nModule,
|
||||||
UiModule,
|
UiModule,
|
||||||
|
|
||||||
|
AppLayoutsModule,
|
||||||
|
AppGroupSectionModule,
|
||||||
ChatUiModule,
|
ChatUiModule,
|
||||||
AppChatModule
|
AppChatModule
|
||||||
],
|
],
|
||||||
exports: [...COMPONENTS],
|
exports: [...COMPONENTS, ...DIALOGS],
|
||||||
declarations: [...COMPONENTS],
|
declarations: [...COMPONENTS, ...DIALOGS],
|
||||||
entryComponents: [],
|
entryComponents: [...DIALOGS],
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
provide: UCAP_I18N_NAMESPACE,
|
provide: UCAP_I18N_NAMESPACE,
|
||||||
|
|
|
@ -1,16 +1,23 @@
|
||||||
<ng-container [ngSwitch]="selectorType">
|
<ng-container [ngSwitch]="selectorType">
|
||||||
<app-chat-selector-sticker *ngSwitchCase="'STICKER'">
|
<app-chat-selector-sticker
|
||||||
|
*ngSwitchCase="SelectorType.STICKER"
|
||||||
|
(selectedSticker)="onSelectedSticker($event)"
|
||||||
|
(closeSticker)="selectorType = SelectorType.EMPTY"
|
||||||
|
>
|
||||||
</app-chat-selector-sticker>
|
</app-chat-selector-sticker>
|
||||||
|
|
||||||
<app-chat-selector-translation
|
<app-chat-selector-translation
|
||||||
*ngSwitchCase="'TRANSLATION'"
|
*ngSwitchCase="SelectorType.TRANSLATION"
|
||||||
></app-chat-selector-translation>
|
></app-chat-selector-translation>
|
||||||
|
|
||||||
<app-chat-selector-file-upload *ngSwitchCase="'FILEUPLOAD'">
|
<app-chat-selector-file-upload
|
||||||
|
#fileUploadSelector
|
||||||
|
*ngSwitchCase="SelectorType.FILEUPLOAD"
|
||||||
|
>
|
||||||
</app-chat-selector-file-upload>
|
</app-chat-selector-file-upload>
|
||||||
|
|
||||||
<app-chat-selector-email-send
|
<app-chat-selector-email-send
|
||||||
*ngSwitchCase="'EMAILSENDER'"
|
*ngSwitchCase="SelectorType.EMAILSENDER"
|
||||||
></app-chat-selector-email-send>
|
></app-chat-selector-email-send>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
|
@ -23,13 +30,22 @@
|
||||||
>
|
>
|
||||||
<textarea
|
<textarea
|
||||||
matInput
|
matInput
|
||||||
#replyInput
|
#messageInput
|
||||||
placeholder=""
|
placeholder=""
|
||||||
name="message"
|
name="message"
|
||||||
[matTextareaAutosize]="true"
|
[matTextareaAutosize]="true"
|
||||||
[matAutosizeMaxRows]="20"
|
[matAutosizeMaxRows]="20"
|
||||||
|
(keydown)="onKeydown($event)"
|
||||||
></textarea>
|
></textarea>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
#fileInput
|
||||||
|
style="display: none;"
|
||||||
|
multiple
|
||||||
|
(change)="onChangeFileInput()"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="button-area">
|
<div class="button-area">
|
||||||
<button
|
<button
|
||||||
|
@ -37,8 +53,7 @@
|
||||||
aria-label="attachFile"
|
aria-label="attachFile"
|
||||||
matTooltipPosition="above"
|
matTooltipPosition="above"
|
||||||
matTooltip="{{ 'label.attachFile' | ucapI18n }}"
|
matTooltip="{{ 'label.attachFile' | ucapI18n }}"
|
||||||
matTool
|
(click)="clearSelector(); fileInput.click()"
|
||||||
(click)="onOpenSelector('FILEUPLOAD')"
|
|
||||||
>
|
>
|
||||||
첨부파일
|
첨부파일
|
||||||
</button>
|
</button>
|
||||||
|
@ -47,7 +62,7 @@
|
||||||
aria-label="attachImage"
|
aria-label="attachImage"
|
||||||
matTooltipPosition="above"
|
matTooltipPosition="above"
|
||||||
matTooltip="{{ 'label.attachImage' | ucapI18n }}"
|
matTooltip="{{ 'label.attachImage' | ucapI18n }}"
|
||||||
(click)="onOpenSelector('')"
|
(click)="onOpenSelector(SelectorType.EMPTY)"
|
||||||
>
|
>
|
||||||
이미지
|
이미지
|
||||||
</button>
|
</button>
|
||||||
|
@ -56,7 +71,7 @@
|
||||||
aria-label="screenshot"
|
aria-label="screenshot"
|
||||||
matTooltipPosition="above"
|
matTooltipPosition="above"
|
||||||
matTooltip="{{ 'label.screenshot' | ucapI18n }}"
|
matTooltip="{{ 'label.screenshot' | ucapI18n }}"
|
||||||
(click)="onOpenSelector('')"
|
(click)="onOpenSelector(SelectorType.EMPTY)"
|
||||||
>
|
>
|
||||||
캡쳐 화면 전송
|
캡쳐 화면 전송
|
||||||
</button>
|
</button>
|
||||||
|
@ -65,7 +80,7 @@
|
||||||
aria-label="imoticon"
|
aria-label="imoticon"
|
||||||
matTooltipPosition="above"
|
matTooltipPosition="above"
|
||||||
matTooltip="{{ 'label.imoticon' | ucapI18n }}"
|
matTooltip="{{ 'label.imoticon' | ucapI18n }}"
|
||||||
(click)="onOpenSelector('STICKER')"
|
(click)="onOpenSelector(SelectorType.STICKER)"
|
||||||
>
|
>
|
||||||
이모티콘
|
이모티콘
|
||||||
</button>
|
</button>
|
||||||
|
@ -74,7 +89,7 @@
|
||||||
aria-label="emailSend"
|
aria-label="emailSend"
|
||||||
matTooltipPosition="above"
|
matTooltipPosition="above"
|
||||||
matTooltip="{{ 'label.emailSend' | ucapI18n }}"
|
matTooltip="{{ 'label.emailSend' | ucapI18n }}"
|
||||||
(click)="onOpenSelector('EMAILSENDER')"
|
(click)="onOpenSelector(SelectorType.EMAILSENDER)"
|
||||||
>
|
>
|
||||||
대화내용 메일 전송
|
대화내용 메일 전송
|
||||||
</button>
|
</button>
|
||||||
|
@ -83,7 +98,7 @@
|
||||||
aria-label="translation"
|
aria-label="translation"
|
||||||
matTooltipPosition="above"
|
matTooltipPosition="above"
|
||||||
matTooltip="{{ 'label.translation' | ucapI18n }}"
|
matTooltip="{{ 'label.translation' | ucapI18n }}"
|
||||||
(click)="onOpenSelector('TRANSLATION')"
|
(click)="onOpenSelector(SelectorType.TRANSLATION)"
|
||||||
>
|
>
|
||||||
대화내용 번역
|
대화내용 번역
|
||||||
</button>
|
</button>
|
||||||
|
@ -92,7 +107,7 @@
|
||||||
aria-label="gams"
|
aria-label="gams"
|
||||||
matTooltipPosition="above"
|
matTooltipPosition="above"
|
||||||
matTooltip="{{ 'label.gams' | ucapI18n }}"
|
matTooltip="{{ 'label.gams' | ucapI18n }}"
|
||||||
(click)="onOpenSelector('')"
|
(click)="onOpenSelector(SelectorType.EMPTY)"
|
||||||
>
|
>
|
||||||
+GAMS
|
+GAMS
|
||||||
</button>
|
</button>
|
||||||
|
@ -101,7 +116,7 @@
|
||||||
color="accent"
|
color="accent"
|
||||||
aria-label="send"
|
aria-label="send"
|
||||||
matTooltip="{{ 'label.send' | ucapI18n }}"
|
matTooltip="{{ 'label.send' | ucapI18n }}"
|
||||||
(click)="onOpenSelector('')"
|
(click)="send()"
|
||||||
>
|
>
|
||||||
<mat-icon>send</mat-icon>
|
<mat-icon>send</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Subject } from 'rxjs';
|
import { Subject, of, Observable, forkJoin } from 'rxjs';
|
||||||
import { takeUntil } from 'rxjs/operators';
|
import { takeUntil, map, catchError, take } from 'rxjs/operators';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Component,
|
Component,
|
||||||
|
@ -7,12 +7,61 @@ import {
|
||||||
OnDestroy,
|
OnDestroy,
|
||||||
ChangeDetectionStrategy,
|
ChangeDetectionStrategy,
|
||||||
ChangeDetectorRef,
|
ChangeDetectorRef,
|
||||||
Input
|
Input,
|
||||||
|
ViewChild,
|
||||||
|
ElementRef
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { Store, select } from '@ngrx/store';
|
import { Store, select } from '@ngrx/store';
|
||||||
import { RoomInfo } from '@ucap/protocol-room';
|
|
||||||
import { Dictionary } from '@ngrx/entity';
|
import { Dictionary } from '@ngrx/entity';
|
||||||
|
|
||||||
|
import { RoomInfo } from '@ucap/protocol-room';
|
||||||
|
import {
|
||||||
|
SendRequest as SendEventRequest,
|
||||||
|
EventType
|
||||||
|
} from '@ucap/protocol-event';
|
||||||
|
import { LoginResponse } from '@ucap/protocol-authentication';
|
||||||
|
|
||||||
|
import { ChattingActions } from '@ucap/ng-store-chat';
|
||||||
|
import {
|
||||||
|
LoginSelector,
|
||||||
|
ConfigurationSelector
|
||||||
|
} from '@ucap/ng-store-authentication';
|
||||||
|
import { StickerFilesInfo, KEY_STICKER_HISTORY } from '@ucap/ng-core';
|
||||||
|
import {
|
||||||
|
AlertDialogComponent,
|
||||||
|
AlertDialogData,
|
||||||
|
AlertDialogResult
|
||||||
|
} from '@ucap/ng-ui';
|
||||||
|
import { I18nService } from '@ucap/ng-i18n';
|
||||||
|
import { LogService } from '@ucap/ng-logger';
|
||||||
|
|
||||||
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
|
import {
|
||||||
|
TranslationSaveResponse,
|
||||||
|
MassTalkSaveRequest,
|
||||||
|
FileTalkSaveResponse,
|
||||||
|
FileTalkSaveRequest
|
||||||
|
} from '@ucap/api-common';
|
||||||
|
import { environment } from '@environments';
|
||||||
|
import { LocalStorageService } from '@ucap/ng-web-storage';
|
||||||
|
import { CommonApiService } from '@ucap/ng-api-common';
|
||||||
|
import { LoginSession } from '@app/models/login-session';
|
||||||
|
import { AppAuthenticationService } from '@app/services/app-authentication.service';
|
||||||
|
import { StatusCode, FileUploadItem } from '@ucap/api';
|
||||||
|
import { AppFileService } from '@app/services/app-file.service';
|
||||||
|
import { VersionInfo2Response } from '@ucap/api-public';
|
||||||
|
import { FileUploadSelectorComponent } from '@app/ucap/chat/components/file-upload.selector.component';
|
||||||
|
import { FileUtil } from '@ucap/core';
|
||||||
|
import { AppChatService } from '@app/services/app-chat.service';
|
||||||
|
|
||||||
|
export enum SelectorType {
|
||||||
|
EMPTY = '',
|
||||||
|
STICKER = 'STICKER',
|
||||||
|
TRANSLATION = 'TRANSLATION',
|
||||||
|
FILEUPLOAD = 'FILEUPLOAD',
|
||||||
|
EMAILSENDER = 'EMAILSENDER'
|
||||||
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-sections-chat-form',
|
selector: 'app-sections-chat-form',
|
||||||
templateUrl: './form.section.component.html',
|
templateUrl: './form.section.component.html',
|
||||||
|
@ -30,19 +79,70 @@ export class FormSectionComponent implements OnInit, OnDestroy {
|
||||||
// tslint:disable-next-line: variable-name
|
// tslint:disable-next-line: variable-name
|
||||||
_roomId: string;
|
_roomId: string;
|
||||||
|
|
||||||
|
versionInfo2Res: VersionInfo2Response;
|
||||||
|
loginSession: LoginSession;
|
||||||
|
loginRes: LoginResponse;
|
||||||
|
|
||||||
currentRoomInfo: RoomInfo;
|
currentRoomInfo: RoomInfo;
|
||||||
|
|
||||||
selectorType = '';
|
selectorType: SelectorType = SelectorType.EMPTY;
|
||||||
|
|
||||||
|
/** About Sticker */
|
||||||
|
selectedSticker: StickerFilesInfo;
|
||||||
|
|
||||||
|
/** About Translation */
|
||||||
|
translationSimpleview = false;
|
||||||
|
translationPreview = false;
|
||||||
|
destLocale = 'en'; // default English :: en
|
||||||
|
translationPreviewInfo: {
|
||||||
|
previewInfo: TranslationSaveResponse | null;
|
||||||
|
translationType: EventType.Translation | EventType.MassTranslation;
|
||||||
|
};
|
||||||
|
|
||||||
|
@ViewChild('messageInput', { static: false })
|
||||||
|
messageInput: ElementRef<HTMLTextAreaElement>;
|
||||||
|
@ViewChild('fileInput', { static: false })
|
||||||
|
fileInput: ElementRef<HTMLInputElement>;
|
||||||
|
@ViewChild('fileUploadSelector', { static: false })
|
||||||
|
fileUploadSelector: FileUploadSelectorComponent;
|
||||||
|
|
||||||
|
SelectorType = SelectorType;
|
||||||
|
|
||||||
private ngOnDestroySubject: Subject<boolean>;
|
private ngOnDestroySubject: Subject<boolean>;
|
||||||
constructor(
|
constructor(
|
||||||
|
private appFileService: AppFileService,
|
||||||
|
private appChatService: AppChatService,
|
||||||
private store: Store<any>,
|
private store: Store<any>,
|
||||||
|
private i18nService: I18nService,
|
||||||
|
private dialog: MatDialog,
|
||||||
|
private localStorageService: LocalStorageService,
|
||||||
|
private logService: LogService,
|
||||||
|
private appAuthenticationService: AppAuthenticationService,
|
||||||
|
private commonApiService: CommonApiService,
|
||||||
private changeDetectorRef: ChangeDetectorRef
|
private changeDetectorRef: ChangeDetectorRef
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.ngOnDestroySubject = new Subject<boolean>();
|
this.ngOnDestroySubject = new Subject<boolean>();
|
||||||
|
|
||||||
|
this.store
|
||||||
|
.pipe(
|
||||||
|
takeUntil(this.ngOnDestroySubject),
|
||||||
|
select(ConfigurationSelector.versionInfo2Response)
|
||||||
|
)
|
||||||
|
.subscribe((versionInfo2Res) => {
|
||||||
|
this.versionInfo2Res = versionInfo2Res;
|
||||||
|
});
|
||||||
|
this.store
|
||||||
|
.pipe(takeUntil(this.ngOnDestroySubject), select(LoginSelector.loginRes))
|
||||||
|
.subscribe((loginRes) => {
|
||||||
|
this.loginRes = loginRes;
|
||||||
|
});
|
||||||
|
this.appAuthenticationService
|
||||||
|
.getLoginSession$()
|
||||||
|
.pipe(takeUntil(this.ngOnDestroySubject))
|
||||||
|
.subscribe((loginSession) => (this.loginSession = loginSession));
|
||||||
|
|
||||||
this.store
|
this.store
|
||||||
.pipe(
|
.pipe(
|
||||||
takeUntil(this.ngOnDestroySubject),
|
takeUntil(this.ngOnDestroySubject),
|
||||||
|
@ -65,7 +165,176 @@ export class FormSectionComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onOpenSelector(type: string): void {
|
/** About Selector */
|
||||||
|
onOpenSelector(type: SelectorType): void {
|
||||||
this.selectorType = type;
|
this.selectorType = type;
|
||||||
|
this.changeDetectorRef.detectChanges();
|
||||||
|
}
|
||||||
|
clearSelector(): void {
|
||||||
|
this.selectorType = SelectorType.EMPTY;
|
||||||
|
this.selectedSticker = null;
|
||||||
|
this.changeDetectorRef.detectChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Element Handling */
|
||||||
|
focus(clearField: boolean = true): void {
|
||||||
|
if (!!this.messageInput) {
|
||||||
|
if (!!clearField) {
|
||||||
|
this.messageInput.nativeElement.value = '';
|
||||||
|
|
||||||
|
this.clearSelector();
|
||||||
|
}
|
||||||
|
this.messageInput.nativeElement.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeFileInput(): void {
|
||||||
|
const self = this;
|
||||||
|
const fileList = this.fileInput.nativeElement.files;
|
||||||
|
|
||||||
|
this.appFileService
|
||||||
|
.validUploadFile(fileList, this.versionInfo2Res?.fileAllowSize)
|
||||||
|
.then((result) => {
|
||||||
|
if (!result) {
|
||||||
|
self.fileInput.nativeElement.value = '';
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// selector open
|
||||||
|
self.onOpenSelector(SelectorType.FILEUPLOAD);
|
||||||
|
|
||||||
|
// FileuploadItem Init. & FileSelector Init.
|
||||||
|
const fileUploadItems = FileUploadItem.fromFiles(fileList);
|
||||||
|
if (!!self.fileUploadSelector) {
|
||||||
|
self.fileUploadSelector.onFileSelected(fileUploadItems);
|
||||||
|
}
|
||||||
|
self.fileInput.nativeElement.value = '';
|
||||||
|
|
||||||
|
// File Upload..
|
||||||
|
self.appChatService
|
||||||
|
.sendMessageOfAttachFile(
|
||||||
|
self.loginRes,
|
||||||
|
self.loginSession.deviceType,
|
||||||
|
self.currentRoomInfo.roomId,
|
||||||
|
fileUploadItems
|
||||||
|
)
|
||||||
|
.then((success) => {
|
||||||
|
if (!!success) {
|
||||||
|
self.clearSelector();
|
||||||
|
if (!!self.fileUploadSelector) {
|
||||||
|
self.fileUploadSelector.onUploadComplete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
alert(err);
|
||||||
|
if (!!self.fileUploadSelector) {
|
||||||
|
self.fileUploadSelector.onUploadComplete();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
self.fileInput.nativeElement.value = '';
|
||||||
|
self.logService.error(`validUploadFile ${err}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeydown(event: KeyboardEvent) {
|
||||||
|
if (event.key === 'PageUp' || event.key === 'PageDown') {
|
||||||
|
event.preventDefault();
|
||||||
|
return false;
|
||||||
|
} else if (event.key === 'Enter' && !event.shiftKey) {
|
||||||
|
event.preventDefault();
|
||||||
|
this.send();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onSelectedSticker(stickerInfo: StickerFilesInfo) {
|
||||||
|
this.selectedSticker = stickerInfo;
|
||||||
|
this.focus(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
async send() {
|
||||||
|
const roomId = this.currentRoomInfo.roomId;
|
||||||
|
const userSeq = this.loginRes.userSeq;
|
||||||
|
let message = this.messageInput.nativeElement.value;
|
||||||
|
|
||||||
|
if (!!message || message.trim().length > 0) {
|
||||||
|
message = message.replace(/\t/g, ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Empty Check.
|
||||||
|
if (!this.selectedSticker) {
|
||||||
|
try {
|
||||||
|
if (!message || message.trim().length === 0) {
|
||||||
|
const result = await this.dialog.open<
|
||||||
|
AlertDialogComponent,
|
||||||
|
AlertDialogData,
|
||||||
|
AlertDialogResult
|
||||||
|
>(AlertDialogComponent, {
|
||||||
|
data: {
|
||||||
|
title: this.i18nService.t('errors.label'),
|
||||||
|
message: this.i18nService.t('errors.inputChatMessage')
|
||||||
|
},
|
||||||
|
panelClass: ''
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
this.logService.debug(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
this.selectorType === SelectorType.TRANSLATION &&
|
||||||
|
this.destLocale.trim().length > 0
|
||||||
|
) {
|
||||||
|
/** CASE : Translation */
|
||||||
|
// 번역할 대화 없이 스티커만 전송할 경우.
|
||||||
|
if (!message || message.trim().length === 0) {
|
||||||
|
this.appChatService.sendMessageOfSticker(
|
||||||
|
userSeq,
|
||||||
|
roomId,
|
||||||
|
this.selectedSticker,
|
||||||
|
message
|
||||||
|
);
|
||||||
|
|
||||||
|
this.clearSelector();
|
||||||
|
} else {
|
||||||
|
this.appChatService.sendMessageOfTranslate(
|
||||||
|
this.loginRes,
|
||||||
|
this.loginSession.deviceType,
|
||||||
|
this.destLocale,
|
||||||
|
roomId,
|
||||||
|
message,
|
||||||
|
this.selectedSticker
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (!!this.selectedSticker) {
|
||||||
|
/** CASE : Sticker */
|
||||||
|
this.appChatService.sendMessageOfSticker(
|
||||||
|
userSeq,
|
||||||
|
roomId,
|
||||||
|
this.selectedSticker,
|
||||||
|
message
|
||||||
|
);
|
||||||
|
|
||||||
|
this.clearSelector();
|
||||||
|
} else if (
|
||||||
|
message.trim().length > environment.productConfig.chat.masstextLength
|
||||||
|
) {
|
||||||
|
/** CASE : MASS TEXT */
|
||||||
|
this.appChatService.sendMessageOfMassText(
|
||||||
|
this.loginRes,
|
||||||
|
this.loginSession.deviceType,
|
||||||
|
roomId,
|
||||||
|
message
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
/** CASE : Normal Text */
|
||||||
|
this.appChatService.sendMessageOfNormal(userSeq, roomId, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,6 +144,14 @@ export class ListSectionComponent implements OnInit, OnDestroy {
|
||||||
private ngZone: NgZone,
|
private ngZone: NgZone,
|
||||||
private logService: LogService
|
private logService: LogService
|
||||||
) {
|
) {
|
||||||
|
// default image setting
|
||||||
|
this.defaultProfileImage = this.appChatService.defaultProfileImage;
|
||||||
|
this.defaultProfileImageMulti = this.appChatService.defaultProfileImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.ngOnDestroySubject = new Subject<boolean>();
|
||||||
|
|
||||||
// language setting
|
// language setting
|
||||||
this.translateService.setDefaultLang(this.i18nService.currentLng);
|
this.translateService.setDefaultLang(this.i18nService.currentLng);
|
||||||
this.translateService.use(this.i18nService.currentLng);
|
this.translateService.use(this.i18nService.currentLng);
|
||||||
|
@ -153,14 +161,6 @@ export class ListSectionComponent implements OnInit, OnDestroy {
|
||||||
);
|
);
|
||||||
this.i18nService.setDefaultNamespace('chat');
|
this.i18nService.setDefaultNamespace('chat');
|
||||||
|
|
||||||
// default image setting
|
|
||||||
this.defaultProfileImage = this.appChatService.defaultProfileImage;
|
|
||||||
this.defaultProfileImageMulti = this.appChatService.defaultProfileImage;
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
this.ngOnDestroySubject = new Subject<boolean>();
|
|
||||||
|
|
||||||
this.store
|
this.store
|
||||||
.pipe(
|
.pipe(
|
||||||
takeUntil(this.ngOnDestroySubject),
|
takeUntil(this.ngOnDestroySubject),
|
||||||
|
@ -176,15 +176,20 @@ export class ListSectionComponent implements OnInit, OnDestroy {
|
||||||
this.loginRes = loginRes;
|
this.loginRes = loginRes;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.store
|
combineLatest([
|
||||||
.pipe(takeUntil(this.ngOnDestroySubject), select(RoomSelector.rooms))
|
this.store.pipe(select(RoomSelector.rooms)),
|
||||||
.subscribe((rooms) => {
|
this.store.pipe(select(RoomSelector.standbyRooms))
|
||||||
rooms = (rooms || []).filter((info) => info.isJoinRoom);
|
])
|
||||||
|
.pipe(takeUntil(this.ngOnDestroySubject))
|
||||||
|
.subscribe(([rooms, standbyRooms]) => {
|
||||||
|
rooms = (rooms || []).filter((info) => {
|
||||||
|
return (
|
||||||
|
info.isJoinRoom &&
|
||||||
|
!standbyRooms.find((standbyRoom) => standbyRoom === info.roomId)
|
||||||
|
);
|
||||||
|
});
|
||||||
this.roomList = rooms;
|
this.roomList = rooms;
|
||||||
|
|
||||||
// groupping.
|
|
||||||
this.initGroup();
|
|
||||||
|
|
||||||
this.changeDetectorRef.detectChanges();
|
this.changeDetectorRef.detectChanges();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -218,41 +223,6 @@ export class ListSectionComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
initGroup() {
|
|
||||||
this.roomGroup = [];
|
|
||||||
|
|
||||||
this.roomList.forEach((roomInfo) => {
|
|
||||||
const date = roomInfo.finalEventDate;
|
|
||||||
let division = '';
|
|
||||||
try {
|
|
||||||
const value = this.dateService.get(date, 'LL');
|
|
||||||
|
|
||||||
if (value === 'Invalid date') {
|
|
||||||
division = date;
|
|
||||||
} else {
|
|
||||||
division = value;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
division = date;
|
|
||||||
}
|
|
||||||
|
|
||||||
const index = this.roomGroup.findIndex(
|
|
||||||
(info) => info.division === division
|
|
||||||
);
|
|
||||||
if (index > -1) {
|
|
||||||
this.roomGroup[index] = {
|
|
||||||
...this.roomGroup[index],
|
|
||||||
roomList: [...this.roomGroup[index].roomList, roomInfo]
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
this.roomGroup.push({
|
|
||||||
division,
|
|
||||||
roomList: [roomInfo]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getRoomName(roomInfo: RoomInfo): string {
|
getRoomName(roomInfo: RoomInfo): string {
|
||||||
if (!roomInfo) {
|
if (!roomInfo) {
|
||||||
return '';
|
return '';
|
||||||
|
@ -392,8 +362,8 @@ export class ListSectionComponent implements OnInit, OnDestroy {
|
||||||
ConfirmDialogResult
|
ConfirmDialogResult
|
||||||
>(ConfirmDialogComponent, {
|
>(ConfirmDialogComponent, {
|
||||||
data: {
|
data: {
|
||||||
title: this.i18nService.t('room.dialog.titleExitFromRoom'),
|
title: this.i18nService.t('dialog.title.exitFromRoom'),
|
||||||
html: this.i18nService.t('room.dialog.confirmExitFromRoom')
|
html: this.i18nService.t('dialog.confirmExitFromRoom')
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
<app-chat-message-box
|
<app-chat-message-box
|
||||||
*ngFor="let event of eventList"
|
*ngFor="let event of eventList"
|
||||||
[message]="event"
|
[message]="event"
|
||||||
|
[roomInfo]="currentRoomInfo"
|
||||||
[isMe]="event.senderSeq + '' === loginRes?.userSeq + ''"
|
[isMe]="event.senderSeq + '' === loginRes?.userSeq + ''"
|
||||||
[senderInfo]="getSenderInfo(event.senderSeq)"
|
[senderInfo]="getSenderInfo(event.senderSeq)"
|
||||||
[defaultProfileImage]="defaultProfileImage"
|
[defaultProfileImage]="defaultProfileImage"
|
||||||
|
|
|
@ -21,7 +21,8 @@ import { Chatting } from '@ucap/ng-store-chat/lib/store/chatting/state';
|
||||||
import { ChattingSelector, RoomSelector } from '@ucap/ng-store-chat';
|
import { ChattingSelector, RoomSelector } from '@ucap/ng-store-chat';
|
||||||
import {
|
import {
|
||||||
UserInfo as RoomUserInfo,
|
UserInfo as RoomUserInfo,
|
||||||
UserInfoShort as RoomUserInfoShort
|
UserInfoShort as RoomUserInfoShort,
|
||||||
|
RoomInfo
|
||||||
} from '@ucap/protocol-room';
|
} from '@ucap/protocol-room';
|
||||||
import { LoginResponse } from '@ucap/protocol-authentication';
|
import { LoginResponse } from '@ucap/protocol-authentication';
|
||||||
import {
|
import {
|
||||||
|
@ -31,6 +32,7 @@ import {
|
||||||
import { AppChatService } from '@app/services/app-chat.service';
|
import { AppChatService } from '@app/services/app-chat.service';
|
||||||
import { VersionInfo2Response } from '@ucap/api-public';
|
import { VersionInfo2Response } from '@ucap/api-public';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
import { Dictionary } from '@ngrx/entity';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-sections-chat-message',
|
selector: 'app-sections-chat-message',
|
||||||
|
@ -59,6 +61,7 @@ export class MessageSectionComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
roomIdSubject = new Subject<string>();
|
roomIdSubject = new Subject<string>();
|
||||||
|
|
||||||
|
currentRoomInfo: RoomInfo;
|
||||||
chatting$: Observable<Chatting>;
|
chatting$: Observable<Chatting>;
|
||||||
roomUsers: RoomUserInfoShort[] = [];
|
roomUsers: RoomUserInfoShort[] = [];
|
||||||
// eventList$: Observable<Info<EventJson>[]>;
|
// eventList$: Observable<Info<EventJson>[]>;
|
||||||
|
@ -91,6 +94,19 @@ export class MessageSectionComponent implements OnInit, OnDestroy {
|
||||||
.subscribe((loginRes) => {
|
.subscribe((loginRes) => {
|
||||||
this.loginRes = loginRes;
|
this.loginRes = loginRes;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.store
|
||||||
|
.pipe(
|
||||||
|
takeUntil(this.ngOnDestroySubject),
|
||||||
|
select(
|
||||||
|
(state: any) => state.chat.room.rooms.entities as Dictionary<RoomInfo>
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.subscribe((rooms) => {
|
||||||
|
if (!!this.roomId) {
|
||||||
|
this.currentRoomInfo = rooms[this.roomId];
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
initializeRoomData() {
|
initializeRoomData() {
|
||||||
|
|
86
src/app/sections/chat/dialogs/create.dialog.component.html
Normal file
86
src/app/sections/chat/dialogs/create.dialog.component.html
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
<div class="dialog-container">
|
||||||
|
<app-layouts-default-dialog
|
||||||
|
[disableClose]="false"
|
||||||
|
(closed)="onClosed($event)"
|
||||||
|
>
|
||||||
|
<div appLayoutsDefaultDialog="header">
|
||||||
|
{{ 'dialog.title.newChatRoom' | ucapI18n }}
|
||||||
|
</div>
|
||||||
|
<div class="dialog-body" appLayoutsDefaultDialog="body">
|
||||||
|
<mat-horizontal-stepper
|
||||||
|
[linear]="true"
|
||||||
|
#stepper
|
||||||
|
[selectedIndex]="currentStep"
|
||||||
|
>
|
||||||
|
<mat-step label="Select room type">
|
||||||
|
<div
|
||||||
|
class="normal-room"
|
||||||
|
[ngClass]="
|
||||||
|
isTimer !== undefined && isTimer === false ? 'checked' : ''
|
||||||
|
"
|
||||||
|
(click)="isTimer = false"
|
||||||
|
>
|
||||||
|
<span class="title">{{ 'dialog.normalRoom' | ucapI18n }}</span>
|
||||||
|
<img />
|
||||||
|
<div
|
||||||
|
class="description"
|
||||||
|
[innerHTML]="
|
||||||
|
'dialog.normalRoomDescription'
|
||||||
|
| ucapI18n: { maxCount: maxChatRoomUser }
|
||||||
|
"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="normal-room"
|
||||||
|
[ngClass]="
|
||||||
|
isTimer !== undefined && isTimer === true ? 'checked' : ''
|
||||||
|
"
|
||||||
|
(click)="isTimer = true"
|
||||||
|
>
|
||||||
|
<span class="title">{{ 'dialog.timerRoom' | ucapI18n }}</span>
|
||||||
|
<img />
|
||||||
|
<div
|
||||||
|
class="description"
|
||||||
|
[innerHTML]="
|
||||||
|
'dialog.timerRoomDescription'
|
||||||
|
| ucapI18n: { maxCount: maxChatRoomUser }
|
||||||
|
"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</mat-step>
|
||||||
|
<mat-step label="Select users">
|
||||||
|
<app-group-select-user
|
||||||
|
[isDialog]="true"
|
||||||
|
[checkable]="true"
|
||||||
|
(changeUserList)="onChangeUserList($event)"
|
||||||
|
></app-group-select-user>
|
||||||
|
</mat-step>
|
||||||
|
</mat-horizontal-stepper>
|
||||||
|
</div>
|
||||||
|
<div appLayoutsDefaultDialog="action">
|
||||||
|
<button mat-button (click)="onCancel(stepper)">
|
||||||
|
{{
|
||||||
|
(stepper.selectedIndex === 0
|
||||||
|
? 'dialog.button.cancel'
|
||||||
|
: 'dialog.button.previous'
|
||||||
|
) | ucapI18n
|
||||||
|
}}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
mat-button
|
||||||
|
*ngIf="stepper.selectedIndex === 0"
|
||||||
|
(click)="onConfirm(stepper)"
|
||||||
|
>
|
||||||
|
{{ 'dialog.button.selectRoomUser' | ucapI18n }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
mat-button
|
||||||
|
*ngIf="stepper.selectedIndex === 1"
|
||||||
|
(click)="onOpenRoom(stepper)"
|
||||||
|
>
|
||||||
|
{{ 'dialog.button.openRoom' | ucapI18n }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</app-layouts-default-dialog>
|
||||||
|
</div>
|
|
@ -0,0 +1,9 @@
|
||||||
|
.dialog-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.dialog-body {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { By } from '@angular/platform-browser';
|
||||||
|
import { DebugElement } from '@angular/core';
|
||||||
|
|
||||||
|
import { CreateDialogComponent } from './create.dialog.component';
|
||||||
|
|
||||||
|
describe('ucap::ui-organization::CreateChatDialogComponent', () => {
|
||||||
|
let component: CreateDialogComponent;
|
||||||
|
let fixture: ComponentFixture<CreateDialogComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [CreateDialogComponent]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(CreateDialogComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
132
src/app/sections/chat/dialogs/create.dialog.component.ts
Normal file
132
src/app/sections/chat/dialogs/create.dialog.component.ts
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
import { Subject } from 'rxjs';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Component,
|
||||||
|
OnInit,
|
||||||
|
OnDestroy,
|
||||||
|
ChangeDetectionStrategy,
|
||||||
|
ChangeDetectorRef,
|
||||||
|
Inject,
|
||||||
|
Input
|
||||||
|
} from '@angular/core';
|
||||||
|
|
||||||
|
import {
|
||||||
|
MatDialogRef,
|
||||||
|
MAT_DIALOG_DATA,
|
||||||
|
MatDialog
|
||||||
|
} from '@angular/material/dialog';
|
||||||
|
|
||||||
|
import { UserInfo } from '@ucap/protocol-sync';
|
||||||
|
import { UserInfoSS, UserInfoF, UserInfoDN } from '@ucap/protocol-query';
|
||||||
|
import { UserInfo as RoomUserInfo } from '@ucap/protocol-room';
|
||||||
|
import { MatStepper } from '@angular/material/stepper';
|
||||||
|
import { I18nService } from '@ucap/ng-i18n';
|
||||||
|
import { GroupActions } from '@ucap/ng-store-group';
|
||||||
|
import {
|
||||||
|
AlertDialogComponent,
|
||||||
|
AlertDialogData,
|
||||||
|
AlertDialogResult
|
||||||
|
} from '@ucap/ng-ui';
|
||||||
|
import { environment } from '@environments';
|
||||||
|
import { AppChatService } from '@app/services/app-chat.service';
|
||||||
|
|
||||||
|
export type UserInfoTypes =
|
||||||
|
| UserInfo
|
||||||
|
| UserInfoSS
|
||||||
|
| UserInfoF
|
||||||
|
| UserInfoDN
|
||||||
|
| RoomUserInfo;
|
||||||
|
|
||||||
|
export interface CreateDialogData {}
|
||||||
|
export interface CreateDialogResult {
|
||||||
|
userSeqs: string[];
|
||||||
|
isTimer: boolean | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-dialog-chat-create',
|
||||||
|
templateUrl: './create.dialog.component.html',
|
||||||
|
styleUrls: ['./create.dialog.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
|
})
|
||||||
|
export class CreateDialogComponent implements OnInit, OnDestroy {
|
||||||
|
currentStep = 0;
|
||||||
|
maxChatRoomUser: number;
|
||||||
|
|
||||||
|
isTimer: boolean | undefined;
|
||||||
|
selectedUserList: UserInfoTypes[] = [];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public dialogRef: MatDialogRef<CreateDialogData, CreateDialogResult>,
|
||||||
|
@Inject(MAT_DIALOG_DATA) public data: CreateDialogData,
|
||||||
|
private i18nService: I18nService,
|
||||||
|
public dialog: MatDialog,
|
||||||
|
private changeDetectorRef: ChangeDetectorRef
|
||||||
|
) {
|
||||||
|
this.maxChatRoomUser = environment.productConfig.chat.maxChatRoomUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {}
|
||||||
|
|
||||||
|
onClosed(event: MouseEvent): void {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
onCancel(stepper: MatStepper) {
|
||||||
|
if (stepper.selectedIndex > 0) {
|
||||||
|
stepper.previous();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
onConfirm(stepper: MatStepper) {
|
||||||
|
// validation.
|
||||||
|
if (this.isTimer === undefined) {
|
||||||
|
this.dialog.open<
|
||||||
|
AlertDialogComponent,
|
||||||
|
AlertDialogData,
|
||||||
|
AlertDialogResult
|
||||||
|
>(AlertDialogComponent, {
|
||||||
|
data: {
|
||||||
|
title: this.i18nService.t('errors.label'),
|
||||||
|
html: this.i18nService.t('errors.emptyOpenRoomType', {
|
||||||
|
maxCount: this.maxChatRoomUser
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
stepper.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
onOpenRoom(stepper: MatStepper) {
|
||||||
|
const userSeqs: string[] = [];
|
||||||
|
|
||||||
|
this.selectedUserList.map((user) => userSeqs.push(user.seq.toString()));
|
||||||
|
|
||||||
|
if (this.selectedUserList.length >= this.maxChatRoomUser) {
|
||||||
|
this.dialog.open<
|
||||||
|
AlertDialogComponent,
|
||||||
|
AlertDialogData,
|
||||||
|
AlertDialogResult
|
||||||
|
>(AlertDialogComponent, {
|
||||||
|
data: {
|
||||||
|
title: this.i18nService.t('errors.label'),
|
||||||
|
html: this.i18nService.t('errors.maxCountOfRoomMemberWith', {
|
||||||
|
maxCount: this.maxChatRoomUser
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open Room.
|
||||||
|
this.dialogRef.close({ userSeqs, isTimer: this.isTimer });
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeUserList(selectedUserList: UserInfoTypes[]) {
|
||||||
|
this.selectedUserList = selectedUserList;
|
||||||
|
}
|
||||||
|
}
|
3
src/app/sections/chat/dialogs/index.ts
Normal file
3
src/app/sections/chat/dialogs/index.ts
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
import { CreateDialogComponent } from './create.dialog.component';
|
||||||
|
|
||||||
|
export const DIALOGS = [CreateDialogComponent];
|
|
@ -3,11 +3,12 @@ import { SearchSectionComponent } from './search.section.component';
|
||||||
import { ProfileSectionComponent } from './profile.section.component';
|
import { ProfileSectionComponent } from './profile.section.component';
|
||||||
import { InfoSectionComponent } from './info.section.component';
|
import { InfoSectionComponent } from './info.section.component';
|
||||||
import { SelectUserSectionComponent } from './select-user.section.component';
|
import { SelectUserSectionComponent } from './select-user.section.component';
|
||||||
|
import { SelectGroupSectionComponent } from './select-group.section.component';
|
||||||
export const COMPONENTS = [
|
export const COMPONENTS = [
|
||||||
ListSectionComponent,
|
ListSectionComponent,
|
||||||
SearchSectionComponent,
|
SearchSectionComponent,
|
||||||
ProfileSectionComponent,
|
ProfileSectionComponent,
|
||||||
InfoSectionComponent,
|
InfoSectionComponent,
|
||||||
SelectUserSectionComponent
|
SelectUserSectionComponent,
|
||||||
|
SelectGroupSectionComponent
|
||||||
];
|
];
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<div
|
<div
|
||||||
*ngIf="!!searchObj && !searchObj.isShowSearch"
|
*ngIf="!!searchData && !searchData.bySearch"
|
||||||
fxFlexFill
|
fxFlexFill
|
||||||
class="list-container"
|
class="list-container"
|
||||||
>
|
>
|
||||||
|
@ -8,20 +8,13 @@
|
||||||
[showType]="showType"
|
[showType]="showType"
|
||||||
(clicked)="onClickUser($event)"
|
(clicked)="onClickUser($event)"
|
||||||
(selectGroupMenu)="onSelectGroupMenu($event)"
|
(selectGroupMenu)="onSelectGroupMenu($event)"
|
||||||
|
(selectProfileMenu)="onSelectProfileMenu($event)"
|
||||||
(profileMenu)="onProfileMenu($event)"
|
(profileMenu)="onProfileMenu($event)"
|
||||||
></app-group-expansion>
|
></app-group-expansion>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="!!searchObj && searchObj.isShowSearch" class="search-wrpper">
|
<div *ngIf="!!searchData && searchData.bySearch" class="search-wrpper">
|
||||||
<perfect-scrollbar fxFlex="1 1 auto">
|
<app-group-profile-list
|
||||||
<app-group-profile-list-item
|
[searchData]="_searchData"
|
||||||
*ngFor="let userInfo of searchUserInfos"
|
|
||||||
[userInfo]="userInfo"
|
|
||||||
[checkable]="checkable"
|
[checkable]="checkable"
|
||||||
defaultProfileImage="assets/images/img_nophoto_50.png"
|
></app-group-profile-list>
|
||||||
(checkUser)="onCheckUser($event)"
|
|
||||||
(click)="onClickSearchUser($event, userInfo)"
|
|
||||||
[presence]="getStatusBulkInfo(userInfo) | async"
|
|
||||||
>
|
|
||||||
</app-group-profile-list-item>
|
|
||||||
</perfect-scrollbar>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -29,7 +29,7 @@ import { LogService } from '@ucap/ng-logger';
|
||||||
import { ExpansionComponent as AppExpansionComponent } from '@app/ucap/group/components/expansion.component';
|
import { ExpansionComponent as AppExpansionComponent } from '@app/ucap/group/components/expansion.component';
|
||||||
import { SessionStorageService } from '@ucap/ng-web-storage';
|
import { SessionStorageService } from '@ucap/ng-web-storage';
|
||||||
import { LoginSelector } from '@ucap/ng-store-authentication';
|
import { LoginSelector } from '@ucap/ng-store-authentication';
|
||||||
import { GroupActions } from '@ucap/ng-store-group';
|
import { GroupActions, BuddyActions } from '@ucap/ng-store-group';
|
||||||
import { I18nService } from '@ucap/ng-i18n';
|
import { I18nService } from '@ucap/ng-i18n';
|
||||||
|
|
||||||
import { AppAuthenticationService } from '@app/services/app-authentication.service';
|
import { AppAuthenticationService } from '@app/services/app-authentication.service';
|
||||||
|
@ -52,7 +52,22 @@ import {
|
||||||
AlertDialogData,
|
AlertDialogData,
|
||||||
AlertDialogResult
|
AlertDialogResult
|
||||||
} from '@ucap/ng-ui';
|
} from '@ucap/ng-ui';
|
||||||
|
import {
|
||||||
|
ManageDialogComponent,
|
||||||
|
ManageDialogData,
|
||||||
|
ManageDialogResult
|
||||||
|
} from '../dialogs/manage.dialog.component';
|
||||||
|
|
||||||
import { PresenceActions, PresenceSelector } from '@ucap/ng-store-organization';
|
import { PresenceActions, PresenceSelector } from '@ucap/ng-store-organization';
|
||||||
|
import { GroupUserDialaogType } from '@app/types';
|
||||||
|
import { EditInlineInputDialogComponent } from '../dialogs/edit-inline-input.dialog.component';
|
||||||
|
import {
|
||||||
|
EditUserDialogComponent,
|
||||||
|
EditUserDialogData,
|
||||||
|
EditUserDialogResult
|
||||||
|
} from '../dialogs/edit-user.dialog.component';
|
||||||
|
import { SearchData } from '@app/ucap/organization/models/search-data';
|
||||||
|
import { UserStore } from '@app/models/user-store';
|
||||||
|
|
||||||
export type UserInfoTypes =
|
export type UserInfoTypes =
|
||||||
| UserInfo
|
| UserInfo
|
||||||
|
@ -81,24 +96,34 @@ export class GroupVirtualScrollStrategy extends FixedSizeVirtualScrollStrategy {
|
||||||
})
|
})
|
||||||
export class ListSectionComponent implements OnInit, OnDestroy {
|
export class ListSectionComponent implements OnInit, OnDestroy {
|
||||||
@Input()
|
@Input()
|
||||||
set searchObj(obj: {
|
set searchData(searchData: SearchData) {
|
||||||
isShowSearch: boolean;
|
this._searchData = searchData;
|
||||||
companyCode: string;
|
if (!searchData) {
|
||||||
searchWord: string;
|
this._searchData = {
|
||||||
}) {
|
companyCode: this.userStore.companyCode
|
||||||
this._searchObj = obj;
|
};
|
||||||
if (obj.isShowSearch && obj.searchWord.localeCompare('') !== 0) {
|
|
||||||
this.onOrganizationTenantSearch(obj);
|
|
||||||
} else {
|
} else {
|
||||||
this._searchObj.isShowSearch = false;
|
if (!this._searchData.companyCode) {
|
||||||
|
this._searchData.companyCode = this.userStore.companyCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
searchData.bySearch &&
|
||||||
|
searchData.searchWord.localeCompare('') !== 0
|
||||||
|
) {
|
||||||
|
this.onOrganizationTenantSearch(searchData);
|
||||||
|
} else {
|
||||||
|
this._searchData.isShowSearch = false;
|
||||||
this.searchUserInfos = [];
|
this.searchUserInfos = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get searchObj() {
|
|
||||||
return this._searchObj;
|
|
||||||
}
|
}
|
||||||
_searchObj: any;
|
|
||||||
|
get searchData() {
|
||||||
|
return this._searchData;
|
||||||
|
}
|
||||||
|
// tslint:disable-next-line: variable-name
|
||||||
|
_searchData: any;
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
checkable = false;
|
checkable = false;
|
||||||
|
@ -120,6 +145,7 @@ export class ListSectionComponent implements OnInit, OnDestroy {
|
||||||
searchUserInfos: UserInfoSS[] = [];
|
searchUserInfos: UserInfoSS[] = [];
|
||||||
|
|
||||||
private ngOnDestroySubject = new Subject<boolean>();
|
private ngOnDestroySubject = new Subject<boolean>();
|
||||||
|
private userStore: UserStore;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private router: Router,
|
private router: Router,
|
||||||
|
@ -132,6 +158,7 @@ export class ListSectionComponent implements OnInit, OnDestroy {
|
||||||
private queryProtocolService: QueryProtocolService,
|
private queryProtocolService: QueryProtocolService,
|
||||||
public dialog: MatDialog
|
public dialog: MatDialog
|
||||||
) {
|
) {
|
||||||
|
this.userStore = this.appAuthenticationService.getUserStore();
|
||||||
this.i18nService.setDefaultNamespace('group');
|
this.i18nService.setDefaultNamespace('group');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,19 +178,15 @@ export class ListSectionComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onOrganizationTenantSearch(obj: {
|
onOrganizationTenantSearch(searchData: SearchData) {
|
||||||
isShowSearch: boolean;
|
|
||||||
companyCode: string;
|
|
||||||
searchWord: string;
|
|
||||||
}) {
|
|
||||||
const searchUserInfos: UserInfoSS[] = [];
|
const searchUserInfos: UserInfoSS[] = [];
|
||||||
|
|
||||||
this.queryProtocolService
|
this.queryProtocolService
|
||||||
.deptUser({
|
.deptUser({
|
||||||
divCd: 'GRP',
|
divCd: 'GRP',
|
||||||
companyCode: this._searchObj.companyCode,
|
companyCode: searchData.companyCode,
|
||||||
searchRange: DeptSearchType.All,
|
searchRange: DeptSearchType.All,
|
||||||
search: this._searchObj.searchWord,
|
search: searchData.searchWord,
|
||||||
senderCompanyCode: this.loginRes.userInfo.companyCode,
|
senderCompanyCode: this.loginRes.userInfo.companyCode,
|
||||||
senderEmployeeType: this.loginRes.userInfo.employeeType
|
senderEmployeeType: this.loginRes.userInfo.employeeType
|
||||||
})
|
})
|
||||||
|
@ -234,7 +257,11 @@ export class ListSectionComponent implements OnInit, OnDestroy {
|
||||||
onProfileMenu(event) {
|
onProfileMenu(event) {
|
||||||
console.log(event);
|
console.log(event);
|
||||||
}
|
}
|
||||||
onSelectGroupMenu(params: { menuType: string; group: GroupDetailData }) {
|
onSelectGroupMenu(params: {
|
||||||
|
menuType: string;
|
||||||
|
groupBuddyList: { group: GroupDetailData; buddyList: UserInfo[] };
|
||||||
|
rect: any;
|
||||||
|
}) {
|
||||||
switch (params.menuType) {
|
switch (params.menuType) {
|
||||||
case 'CHAT':
|
case 'CHAT':
|
||||||
{
|
{
|
||||||
|
@ -266,10 +293,31 @@ export class ListSectionComponent implements OnInit, OnDestroy {
|
||||||
break;
|
break;
|
||||||
case 'RENAME':
|
case 'RENAME':
|
||||||
{
|
{
|
||||||
|
this.renameGroup(params);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'MANAGE_MEMBER':
|
case 'MANAGE_MEMBER':
|
||||||
{
|
{
|
||||||
|
const dialogRef = this.dialog.open<
|
||||||
|
ManageDialogComponent,
|
||||||
|
ManageDialogData,
|
||||||
|
ManageDialogResult
|
||||||
|
>(ManageDialogComponent, {
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
data: {
|
||||||
|
title: '그룹 멤버 관리',
|
||||||
|
groupBuddyList: params.groupBuddyList
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dialogRef
|
||||||
|
.afterClosed()
|
||||||
|
.pipe(take(1))
|
||||||
|
.subscribe((result) => {
|
||||||
|
if (!!result && !!result.type) {
|
||||||
|
this.manageGroup(result);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'DELETE':
|
case 'DELETE':
|
||||||
|
@ -289,7 +337,7 @@ export class ListSectionComponent implements OnInit, OnDestroy {
|
||||||
.pipe(take(1))
|
.pipe(take(1))
|
||||||
.subscribe((result) => {
|
.subscribe((result) => {
|
||||||
if (!!result && !!result.choice) {
|
if (!!result && !!result.choice) {
|
||||||
this.store.dispatch(GroupActions.del({ group: params.group }));
|
GroupActions.del({ group: params.groupBuddyList.group });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -298,41 +346,168 @@ export class ListSectionComponent implements OnInit, OnDestroy {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// onEditGroupName(params: { editName: string; group: GroupDetailData }) {
|
|
||||||
// if (params.editName.localeCompare('') === 0) {
|
onSelectProfileMenu(params: {
|
||||||
// const dialogRef = this.dialog.open<
|
menuType: string;
|
||||||
// AlertDialogComponent,
|
userInfo: UserInfoF;
|
||||||
// AlertDialogData,
|
group: GroupDetailData;
|
||||||
// AlertDialogResult
|
rect: any;
|
||||||
// >(AlertDialogComponent, {
|
}) {
|
||||||
// data: {
|
switch (params.menuType) {
|
||||||
// title: this.i18nService.t('moreMenu.error.label'),
|
case 'REGISTER_FAVORITE':
|
||||||
// html: this.i18nService.t('moreMenu.error.requireName')
|
this.store.dispatch(
|
||||||
// }
|
BuddyActions.update({
|
||||||
// });
|
req: {
|
||||||
// dialogRef
|
seq: Number(params.userInfo.seq),
|
||||||
// .afterClosed()
|
isFavorit: !params.userInfo.isFavorit
|
||||||
// .pipe(
|
}
|
||||||
// take(1),
|
})
|
||||||
// map((result) => {}),
|
);
|
||||||
// catchError((err) => {
|
break;
|
||||||
// return of(err);
|
case 'NICKNAME':
|
||||||
// })
|
{
|
||||||
// )
|
this.editNickname(params.userInfo, params.rect);
|
||||||
// .subscribe();
|
}
|
||||||
// return;
|
break;
|
||||||
// }
|
case 'COPY_BUDDY':
|
||||||
// this.store.dispatch(
|
this.editUserDialog('COPY_BUDDY', params.group, params.userInfo);
|
||||||
// GroupActions.update({
|
break;
|
||||||
// req: {
|
case 'MOVE_BUDDY':
|
||||||
// groupSeq: params.group.seq,
|
this.editUserDialog('MOVE_BUDDY', params.group, params.userInfo);
|
||||||
// groupName: params.editName,
|
break;
|
||||||
// userSeqs: params.group.userSeqs
|
case 'REMOVE_BUDDY':
|
||||||
// }
|
{
|
||||||
// })
|
this.removeBuddy(params.userInfo, params.group);
|
||||||
// );
|
}
|
||||||
// console.log(params.editName);
|
break;
|
||||||
// }
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private renameGroup(params: {
|
||||||
|
menuType: string;
|
||||||
|
groupBuddyList: { group: GroupDetailData; buddyList: UserInfo[] };
|
||||||
|
rect: any;
|
||||||
|
}) {
|
||||||
|
const paramGroup = params.groupBuddyList.group;
|
||||||
|
|
||||||
|
const dialogRef = this.dialog.open(EditInlineInputDialogComponent, {
|
||||||
|
width: params.rect.width,
|
||||||
|
height: params.rect.height,
|
||||||
|
panelClass: 'ucap-edit-group-name-dialog',
|
||||||
|
data: {
|
||||||
|
curValue: paramGroup.name,
|
||||||
|
placeholder: '그룹명을 입력하세요.',
|
||||||
|
left: params.rect.left,
|
||||||
|
top: params.rect.top
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
dialogRef
|
||||||
|
.afterClosed()
|
||||||
|
.pipe(
|
||||||
|
take(1),
|
||||||
|
map((result) => {
|
||||||
|
if (
|
||||||
|
!!result &&
|
||||||
|
result.choice &&
|
||||||
|
result.curValue.localeCompare(paramGroup.name) !== 0
|
||||||
|
) {
|
||||||
|
this.store.dispatch(
|
||||||
|
GroupActions.update({
|
||||||
|
req: {
|
||||||
|
groupSeq: paramGroup.seq,
|
||||||
|
groupName: result.curValue,
|
||||||
|
userSeqs: paramGroup.userSeqs
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
catchError((err) => {
|
||||||
|
return of(err);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.subscribe();
|
||||||
|
}
|
||||||
|
private manageGroup(result: ManageDialogResult) {
|
||||||
|
let targetGroup: GroupDetailData;
|
||||||
|
let targetUserSeqs: string[];
|
||||||
|
|
||||||
|
if (result.type === GroupUserDialaogType.Add) {
|
||||||
|
targetGroup = result.group;
|
||||||
|
targetUserSeqs = [];
|
||||||
|
result.selelctUserList.forEach((userInfo) => {
|
||||||
|
targetUserSeqs.push(userInfo.seq + '');
|
||||||
|
});
|
||||||
|
|
||||||
|
this.store.dispatch(
|
||||||
|
GroupActions.updateMember({ targetGroup, targetUserSeqs })
|
||||||
|
);
|
||||||
|
} else if (result.type === GroupUserDialaogType.Copy) {
|
||||||
|
if (!!result.selectGroupList && result.selectGroupList.length > 0) {
|
||||||
|
result.selectGroupList.forEach((g) => {
|
||||||
|
targetGroup = g;
|
||||||
|
targetUserSeqs = [];
|
||||||
|
|
||||||
|
g.userSeqs.map((seq) => {
|
||||||
|
targetUserSeqs.push(seq);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (targetUserSeqs.length === 0) {
|
||||||
|
result.selelctUserList.forEach((user) => {
|
||||||
|
targetUserSeqs.push(user.seq as any);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
result.selelctUserList.forEach((user) => {
|
||||||
|
const find = targetUserSeqs.indexOf(user.seq as any);
|
||||||
|
if (find < 0) {
|
||||||
|
targetUserSeqs.push(user.seq as any);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.store.dispatch(
|
||||||
|
GroupActions.updateMember({ targetGroup, targetUserSeqs })
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (result.type === GroupUserDialaogType.Move) {
|
||||||
|
const fromGroup = result.group;
|
||||||
|
let toGroup: GroupDetailData;
|
||||||
|
targetUserSeqs = [];
|
||||||
|
|
||||||
|
if (!!result.selectGroupList && result.selectGroupList.length > 0) {
|
||||||
|
result.selectGroupList.forEach((g) => {
|
||||||
|
toGroup = g;
|
||||||
|
targetUserSeqs = [];
|
||||||
|
|
||||||
|
result.selelctUserList.forEach((user) => {
|
||||||
|
targetUserSeqs.push(user.seq as any);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.store.dispatch(
|
||||||
|
GroupActions.moveMember({
|
||||||
|
fromGroup,
|
||||||
|
toGroup,
|
||||||
|
targetUserSeq: targetUserSeqs
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (result.type === GroupUserDialaogType.Create) {
|
||||||
|
targetUserSeqs = [];
|
||||||
|
result.selelctUserList.forEach((userInfo) => {
|
||||||
|
targetUserSeqs.push(userInfo.seq + '');
|
||||||
|
});
|
||||||
|
|
||||||
|
this.store.dispatch(
|
||||||
|
GroupActions.create({
|
||||||
|
groupName: result.groupName,
|
||||||
|
targetUserSeqs
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
getStatusBulkInfo(buddy: UserInfoTypes) {
|
getStatusBulkInfo(buddy: UserInfoTypes) {
|
||||||
return this.store.pipe(
|
return this.store.pipe(
|
||||||
|
@ -342,4 +517,188 @@ export class ListSectionComponent implements OnInit, OnDestroy {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private editUserDialog(
|
||||||
|
type: string,
|
||||||
|
group: GroupDetailData,
|
||||||
|
userInfo: UserInfoTypes
|
||||||
|
) {
|
||||||
|
let title = '';
|
||||||
|
let dialogType: GroupUserDialaogType;
|
||||||
|
if (type === 'COPY_BUDDY') {
|
||||||
|
title = '멤버 복사';
|
||||||
|
dialogType = GroupUserDialaogType.Copy;
|
||||||
|
} else {
|
||||||
|
title = '멤버 이동';
|
||||||
|
dialogType = GroupUserDialaogType.Move;
|
||||||
|
}
|
||||||
|
const dialogRef = this.dialog.open<
|
||||||
|
EditUserDialogComponent,
|
||||||
|
EditUserDialogData,
|
||||||
|
EditUserDialogResult
|
||||||
|
>(EditUserDialogComponent, {
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
data: {
|
||||||
|
title,
|
||||||
|
type: dialogType,
|
||||||
|
group,
|
||||||
|
userInfo
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dialogRef
|
||||||
|
.afterClosed()
|
||||||
|
.pipe(
|
||||||
|
take(1),
|
||||||
|
map((result: EditUserDialogResult) => {
|
||||||
|
let targetGroup: GroupDetailData;
|
||||||
|
let targetUserSeqs: string[];
|
||||||
|
if (result.type === GroupUserDialaogType.Add) {
|
||||||
|
targetGroup = result.group;
|
||||||
|
targetUserSeqs = [];
|
||||||
|
result.selelctUserList.forEach((u) => {
|
||||||
|
targetUserSeqs.push(u.seq + '');
|
||||||
|
});
|
||||||
|
this.store.dispatch(
|
||||||
|
GroupActions.updateMember({ targetGroup, targetUserSeqs })
|
||||||
|
);
|
||||||
|
} else if (result.type === GroupUserDialaogType.Copy) {
|
||||||
|
if (!!result.selectGroupList && result.selectGroupList.length > 0) {
|
||||||
|
result.selectGroupList.forEach((g) => {
|
||||||
|
targetGroup = g;
|
||||||
|
targetUserSeqs = [];
|
||||||
|
g.userSeqs.map((seq) => {
|
||||||
|
targetUserSeqs.push(seq);
|
||||||
|
});
|
||||||
|
if (targetUserSeqs.length === 0) {
|
||||||
|
result.selelctUserList.forEach((user) => {
|
||||||
|
targetUserSeqs.push(user.seq as any);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
result.selelctUserList.forEach((user) => {
|
||||||
|
const find = targetUserSeqs.indexOf(user.seq as any);
|
||||||
|
if (find < 0) {
|
||||||
|
targetUserSeqs.push(user.seq as any);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.store.dispatch(
|
||||||
|
GroupActions.updateMember({ targetGroup, targetUserSeqs })
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (result.type === GroupUserDialaogType.Move) {
|
||||||
|
const fromGroup = result.group;
|
||||||
|
let toGroup: GroupDetailData;
|
||||||
|
targetUserSeqs = [];
|
||||||
|
if (!!result.selectGroupList && result.selectGroupList.length > 0) {
|
||||||
|
result.selectGroupList.forEach((g) => {
|
||||||
|
toGroup = g;
|
||||||
|
targetUserSeqs = [];
|
||||||
|
result.selelctUserList.forEach((user) => {
|
||||||
|
targetUserSeqs.push(user.seq as any);
|
||||||
|
});
|
||||||
|
this.store.dispatch(
|
||||||
|
GroupActions.moveMember({
|
||||||
|
fromGroup,
|
||||||
|
toGroup,
|
||||||
|
targetUserSeq: targetUserSeqs
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (result.type === GroupUserDialaogType.Create) {
|
||||||
|
targetUserSeqs = [];
|
||||||
|
result.selelctUserList.forEach((u) => {
|
||||||
|
targetUserSeqs.push(u.seq + '');
|
||||||
|
});
|
||||||
|
this.store.dispatch(
|
||||||
|
GroupActions.create({
|
||||||
|
groupName: result.groupName,
|
||||||
|
targetUserSeqs
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
catchError((err) => {
|
||||||
|
return of(err);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.subscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
private removeBuddy(userInfo: UserInfoF, group: GroupDetailData) {
|
||||||
|
const dialogRef = this.dialog.open<
|
||||||
|
ConfirmDialogComponent,
|
||||||
|
ConfirmDialogData,
|
||||||
|
ConfirmDialogResult
|
||||||
|
>(ConfirmDialogComponent, {
|
||||||
|
data: {
|
||||||
|
title: '',
|
||||||
|
html: this.i18nService.t('label.confirmRemoveBuddy')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dialogRef
|
||||||
|
.afterClosed()
|
||||||
|
.pipe(
|
||||||
|
take(1),
|
||||||
|
map((result) => {
|
||||||
|
if (!!result && result.choice) {
|
||||||
|
const trgtUserSeq = group.userSeqs.filter(
|
||||||
|
(user) => user + '' !== userInfo.seq + ''
|
||||||
|
);
|
||||||
|
|
||||||
|
this.store.dispatch(
|
||||||
|
GroupActions.updateMember({
|
||||||
|
targetGroup: group,
|
||||||
|
targetUserSeqs: trgtUserSeq
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
catchError((err) => {
|
||||||
|
return of(err);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.subscribe();
|
||||||
|
}
|
||||||
|
private editNickname(userInfo: UserInfoF, rect: any) {
|
||||||
|
const dialogRef = this.dialog.open(EditInlineInputDialogComponent, {
|
||||||
|
width: rect.width - 30 + '',
|
||||||
|
height: rect.height,
|
||||||
|
panelClass: 'ucap-edit-group-name-dialog',
|
||||||
|
data: {
|
||||||
|
curValue: userInfo.nickName,
|
||||||
|
placeholder: '닉네임을 설정하세요.',
|
||||||
|
left: rect.left + 70,
|
||||||
|
top: rect.top
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
dialogRef
|
||||||
|
.afterClosed()
|
||||||
|
.pipe(
|
||||||
|
take(1),
|
||||||
|
map((result) => {
|
||||||
|
if (
|
||||||
|
!!result &&
|
||||||
|
result.choice &&
|
||||||
|
result.curValue.localeCompare(userInfo.nickName) !== 0
|
||||||
|
) {
|
||||||
|
this.store.dispatch(
|
||||||
|
BuddyActions.nickname({
|
||||||
|
req: {
|
||||||
|
userSeq: Number(userInfo.seq),
|
||||||
|
nickname: result.curValue
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
catchError((err) => {
|
||||||
|
return of(err);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.subscribe();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
<div fxFlexFill>
|
||||||
|
<div fxFlex class="container">
|
||||||
|
<!-- search start-->
|
||||||
|
<div>
|
||||||
|
<app-organization-search-for-tenant
|
||||||
|
placeholder="이름 부서명, 전화번호, 이메일"
|
||||||
|
[(searchData)]="companySearchData"
|
||||||
|
(canceled)="onCanceled()"
|
||||||
|
>
|
||||||
|
</app-organization-search-for-tenant>
|
||||||
|
</div>
|
||||||
|
<!-- search end-->
|
||||||
|
|
||||||
|
<div *ngIf="!isSearch">
|
||||||
|
<form name="inputForm" [formGroup]="inputForm" novalidate>
|
||||||
|
<mat-form-field
|
||||||
|
hintLabel="금지단어[-,_]"
|
||||||
|
style="display: block; margin-bottom: 10px;"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
matInput
|
||||||
|
#input
|
||||||
|
maxlength="20"
|
||||||
|
placeholder="그룹명을 입력하세요."
|
||||||
|
formControlName="groupName"
|
||||||
|
(keyup)="onKeyupGroupName()"
|
||||||
|
/>
|
||||||
|
<mat-hint align="end">{{ input.value?.length || 0 }}/20</mat-hint>
|
||||||
|
<!-- <mat-error *ngIf="inputForm.get('groupName').hasError('groupNameBanned')"> -->
|
||||||
|
<!-- {{
|
||||||
|
'group.errors.bannedWords'
|
||||||
|
| translate: { bannedWords: appService.bannedGroupNames.join(',') }
|
||||||
|
}} -->
|
||||||
|
<!-- 금지단어[-,_] -->
|
||||||
|
<!-- </mat-error> -->
|
||||||
|
<!-- <mat-error *ngIf="inputForm.get('groupName').hasError('groupNameSamed')"> -->
|
||||||
|
<!-- {{ 'group.errors.sameNameExist' | translate }} -->
|
||||||
|
<!-- 이미 존재하는 그룹명입니다. -->
|
||||||
|
<!-- </mat-error> -->
|
||||||
|
</mat-form-field>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div *ngIf="!!groupList && groupList.length > 0">
|
||||||
|
<span>기존 그룹 지정</span>
|
||||||
|
<div fxFlexFill class="group-list-container">
|
||||||
|
<div *ngFor="let group of groupList">
|
||||||
|
<div *ngIf="checkVisible(group)">
|
||||||
|
<span>{{ group.name }}</span>
|
||||||
|
<div>
|
||||||
|
<mat-checkbox
|
||||||
|
#checkbox
|
||||||
|
[checked]="groupChecked"
|
||||||
|
(change)="onCheckForGroup($event.source, group)"
|
||||||
|
></mat-checkbox>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="!!isSearch" class="search-wrpper" style="height: 400px;">
|
||||||
|
<app-group-profile-list
|
||||||
|
[searchData]="companySearchData"
|
||||||
|
[checkable]="checkable"
|
||||||
|
[isDialog]="isDialog"
|
||||||
|
(toggleCheck)="onToggleCheck($event)"
|
||||||
|
></app-group-profile-list>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,2 @@
|
||||||
|
.profile-container {
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
import { TestBed, async } from '@angular/core/testing';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { SelectGroupSectionComponent } from './select-group.section.component';
|
||||||
|
|
||||||
|
describe('app::sections::group::SelectGroupSectionComponent', () => {
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [RouterTestingModule],
|
||||||
|
declarations: [SelectGroupSectionComponent]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should create the app', () => {
|
||||||
|
const fixture = TestBed.createComponent(SelectGroupSectionComponent);
|
||||||
|
const app = fixture.componentInstance;
|
||||||
|
expect(app).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should have as title 'ucap-lg-web'`, () => {
|
||||||
|
const fixture = TestBed.createComponent(SelectGroupSectionComponent);
|
||||||
|
const app = fixture.componentInstance;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render title', () => {
|
||||||
|
const fixture = TestBed.createComponent(SelectGroupSectionComponent);
|
||||||
|
fixture.detectChanges();
|
||||||
|
const compiled = fixture.nativeElement;
|
||||||
|
expect(compiled.querySelector('.content span').textContent).toContain(
|
||||||
|
'ucap-lg-web app is running!'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,226 @@
|
||||||
|
import {
|
||||||
|
Component,
|
||||||
|
OnInit,
|
||||||
|
OnDestroy,
|
||||||
|
ChangeDetectionStrategy,
|
||||||
|
ChangeDetectorRef,
|
||||||
|
Input,
|
||||||
|
Output,
|
||||||
|
EventEmitter
|
||||||
|
} from '@angular/core';
|
||||||
|
|
||||||
|
import { Subject, of } from 'rxjs';
|
||||||
|
import { Store, select } from '@ngrx/store';
|
||||||
|
import { takeUntil, take, map, catchError } from 'rxjs/operators';
|
||||||
|
import {
|
||||||
|
LoginSelector,
|
||||||
|
AuthorizationSelector
|
||||||
|
} from '@ucap/ng-store-authentication';
|
||||||
|
import { LoginResponse } from '@ucap/protocol-authentication';
|
||||||
|
import { QueryProtocolService } from '@ucap/ng-protocol-query';
|
||||||
|
import {
|
||||||
|
UserInfoSS,
|
||||||
|
AuthResponse,
|
||||||
|
DeptSearchType,
|
||||||
|
UserInfoF,
|
||||||
|
UserInfoDN
|
||||||
|
} from '@ucap/protocol-query';
|
||||||
|
import { GroupSelector } from '@ucap/ng-store-group';
|
||||||
|
import { GroupDetailData, UserInfo } from '@ucap/protocol-sync';
|
||||||
|
import { PresenceActions } from '@ucap/ng-store-organization';
|
||||||
|
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||||
|
import { UserInfo as RoomUserInfo } from '@ucap/protocol-room';
|
||||||
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
|
import {
|
||||||
|
AlertDialogComponent,
|
||||||
|
AlertDialogData,
|
||||||
|
AlertDialogResult
|
||||||
|
} from '@ucap/ng-ui';
|
||||||
|
import { MatCheckbox } from '@angular/material/checkbox';
|
||||||
|
import { SearchData } from '@app/ucap/organization/models/search-data';
|
||||||
|
|
||||||
|
export type UserInfoTypes =
|
||||||
|
| UserInfo
|
||||||
|
| UserInfoSS
|
||||||
|
| UserInfoF
|
||||||
|
| UserInfoDN
|
||||||
|
| RoomUserInfo;
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-sections-select-group',
|
||||||
|
templateUrl: './select-group.section.component.html',
|
||||||
|
styleUrls: ['./select-group.section.component.scss'],
|
||||||
|
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
|
})
|
||||||
|
export class SelectGroupSectionComponent implements OnInit, OnDestroy {
|
||||||
|
@Input()
|
||||||
|
isMemberMove: boolean;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
isDialog = false;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
checkable = false;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
curGroup: GroupDetailData;
|
||||||
|
|
||||||
|
@Output()
|
||||||
|
changeUserList: EventEmitter<{
|
||||||
|
checked: boolean;
|
||||||
|
userInfo: UserInfoSS;
|
||||||
|
}> = new EventEmitter();
|
||||||
|
|
||||||
|
@Output()
|
||||||
|
changeGroupList: EventEmitter<GroupDetailData[]> = new EventEmitter();
|
||||||
|
|
||||||
|
@Output()
|
||||||
|
changeGroupName: EventEmitter<string> = new EventEmitter();
|
||||||
|
|
||||||
|
set companySearchData(searchData: SearchData) {
|
||||||
|
this._companySearchData = searchData;
|
||||||
|
this.onChangedCompanySearch();
|
||||||
|
}
|
||||||
|
get companySearchData() {
|
||||||
|
return this._companySearchData;
|
||||||
|
}
|
||||||
|
// tslint:disable-next-line: variable-name
|
||||||
|
_companySearchData: SearchData;
|
||||||
|
|
||||||
|
private ngOnDestroySubject = new Subject<boolean>();
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private store: Store<any>,
|
||||||
|
private queryProtocolService: QueryProtocolService,
|
||||||
|
private changeDetectorRef: ChangeDetectorRef,
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
public dialog: MatDialog
|
||||||
|
) {}
|
||||||
|
|
||||||
|
loginRes: LoginResponse;
|
||||||
|
isSearch = false;
|
||||||
|
searchWord: string;
|
||||||
|
searchUserInfos: UserInfoSS[] = [];
|
||||||
|
groupList: GroupDetailData[];
|
||||||
|
selectedUserList: UserInfoTypes[] = [];
|
||||||
|
selectedGroupList: GroupDetailData[] = [];
|
||||||
|
inputForm: FormGroup;
|
||||||
|
groupChecked = false;
|
||||||
|
|
||||||
|
groupName: string;
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.store
|
||||||
|
.pipe(takeUntil(this.ngOnDestroySubject), select(LoginSelector.loginRes))
|
||||||
|
.subscribe((loginRes) => {
|
||||||
|
this.loginRes = loginRes;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.store
|
||||||
|
.pipe(takeUntil(this.ngOnDestroySubject), select(GroupSelector.groups))
|
||||||
|
.subscribe((groups) => {
|
||||||
|
this.groupList = groups;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.inputForm = this.formBuilder.group({
|
||||||
|
groupName: [
|
||||||
|
this.groupName,
|
||||||
|
[
|
||||||
|
// Validators.required
|
||||||
|
// StringUtil.includes(, CharactorType.Special),
|
||||||
|
// this.checkBanWords(),
|
||||||
|
// this.checkSameName()
|
||||||
|
]
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
if (!!this.ngOnDestroySubject) {
|
||||||
|
this.ngOnDestroySubject.complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeyupGroupName() {
|
||||||
|
this.inputForm.get('groupName').markAsTouched();
|
||||||
|
this.changeGroupName.emit(this.inputForm.get('groupName').value);
|
||||||
|
}
|
||||||
|
|
||||||
|
onCheckForGroup(checbox: MatCheckbox, group: GroupDetailData) {
|
||||||
|
if (
|
||||||
|
this.isMemberMove &&
|
||||||
|
!!this.selectedGroupList &&
|
||||||
|
this.selectedGroupList.length > 0 &&
|
||||||
|
this.selectedGroupList[0].seq !== group.seq
|
||||||
|
) {
|
||||||
|
this.dialog.open<
|
||||||
|
AlertDialogComponent,
|
||||||
|
AlertDialogData,
|
||||||
|
AlertDialogResult
|
||||||
|
>(AlertDialogComponent, {
|
||||||
|
data: {
|
||||||
|
title: '멤버이동',
|
||||||
|
html: '멤버이동은 그룹 여러개를 선택할 수 없습니다.'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
checbox.checked = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
this.selectedGroupList.filter((g) => g.seq === group.seq).length === 0
|
||||||
|
) {
|
||||||
|
this.selectedGroupList = [...this.selectedGroupList, group];
|
||||||
|
} else {
|
||||||
|
this.selectedGroupList = this.selectedGroupList.filter(
|
||||||
|
(g) => g.seq !== group.seq
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.changeGroupList.emit(this.selectedGroupList);
|
||||||
|
}
|
||||||
|
|
||||||
|
// onCheckForUser(params: { isChecked: boolean; userInfo: UserInfoTypes }) {
|
||||||
|
// if (
|
||||||
|
// this.selectedUserList.filter((user) => user.seq === params.userInfo.seq)
|
||||||
|
// .length === 0
|
||||||
|
// ) {
|
||||||
|
// this.selectedUserList = [...this.selectedUserList, params.userInfo];
|
||||||
|
// } else {
|
||||||
|
// this.selectedUserList = this.selectedUserList.filter(
|
||||||
|
// (item) => item.seq !== params.userInfo.seq
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// this.changeUserList.emit(this.selectedUserList);
|
||||||
|
// }
|
||||||
|
|
||||||
|
onToggleCheck(data: { checked: boolean; userInfo: UserInfoSS }) {
|
||||||
|
this.changeUserList.emit(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangedCompanySearch() {
|
||||||
|
this.isSearch = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
onCanceled() {
|
||||||
|
this.isSearch = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
getCheckedUser(userInfo: UserInfoTypes) {
|
||||||
|
if (!!this.selectedUserList && this.selectedUserList.length > 0) {
|
||||||
|
return (
|
||||||
|
this.selectedUserList.filter((item) => item.seq === userInfo.seq)
|
||||||
|
.length > 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
checkVisible(group: GroupDetailData): boolean {
|
||||||
|
if (!!this.curGroup && this.curGroup.seq === group.seq) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,7 @@
|
||||||
<div>
|
<div>
|
||||||
<app-organization-search-for-tenant
|
<app-organization-search-for-tenant
|
||||||
placeholder="이름 부서명, 전화번호, 이메일"
|
placeholder="이름 부서명, 전화번호, 이메일"
|
||||||
(changed)="onChanged($event)"
|
[(searchData)]="companySearchData"
|
||||||
(canceled)="onCanceled()"
|
(canceled)="onCanceled()"
|
||||||
>
|
>
|
||||||
</app-organization-search-for-tenant>
|
</app-organization-search-for-tenant>
|
||||||
|
@ -24,12 +24,13 @@
|
||||||
<div fxFlexFill>
|
<div fxFlexFill>
|
||||||
<div class="organization-tree">
|
<div class="organization-tree">
|
||||||
<app-group-expansion
|
<app-group-expansion
|
||||||
|
style="height: 400px;"
|
||||||
fxFlexFill
|
fxFlexFill
|
||||||
[isDialog]="isDialog"
|
[isDialog]="isDialog"
|
||||||
[selectedUserList]="selectedUserList"
|
[selectedUserList]="selectedUserList"
|
||||||
[checkable]="true"
|
[checkable]="checkable"
|
||||||
(checked)="onCheckUser($event)"
|
(toggleCheckUser)="onToggleCheckUser($event)"
|
||||||
(checkGroup)="onCheckGroup($event)"
|
(toggleCheckGroup)="onToggleCheckGroup($event)"
|
||||||
></app-group-expansion>
|
></app-group-expansion>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -59,73 +60,14 @@
|
||||||
</mat-tab>
|
</mat-tab>
|
||||||
</mat-tab-group>
|
</mat-tab-group>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="!!isSearch" class="search-wrpper">
|
<div *ngIf="!!isSearch" class="search-wrpper" style="height: 400px;">
|
||||||
<perfect-scrollbar fxFlex="1 1 auto">
|
<app-group-profile-list
|
||||||
<app-group-profile-list-item
|
[searchData]="companySearchData"
|
||||||
*ngFor="let userInfo of searchUserInfos"
|
[selectedUser]="selectedUserList"
|
||||||
[userInfo]="userInfo"
|
|
||||||
[checkable]="checkable"
|
[checkable]="checkable"
|
||||||
[isChecked]="getCheckedUser(userInfo)"
|
[isDialog]="isDialog"
|
||||||
defaultProfileImage="assets/images/img_nophoto_50.png"
|
(toggleCheck)="onToggleCheckUser($event)"
|
||||||
(checked)="onCheckUser($event)"
|
></app-group-profile-list>
|
||||||
>
|
|
||||||
</app-group-profile-list-item>
|
|
||||||
</perfect-scrollbar>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<ng-template [ngTemplateOutlet]="selectedUserListTemplate"></ng-template>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ng-template #selectedUserListTemplate>
|
|
||||||
<div class="list-chip">
|
|
||||||
<mat-chip-list aria-label="User selection">
|
|
||||||
<mat-chip
|
|
||||||
*ngFor="let userInfo of selectedUserList"
|
|
||||||
[selected]="getChipsRemoveYn(userInfo)"
|
|
||||||
(removed)="onClickDeleteUser(userInfo)"
|
|
||||||
>
|
|
||||||
<!-- {{ userInfo | ucapTranslate: 'name' }} -->
|
|
||||||
{{ userInfo.name }}
|
|
||||||
<mat-icon matChipRemove *ngIf="getChipsRemoveYn(userInfo)"
|
|
||||||
>clear</mat-icon
|
|
||||||
>
|
|
||||||
</mat-chip>
|
|
||||||
</mat-chip-list>
|
|
||||||
</div>
|
|
||||||
<ng-container
|
|
||||||
*ngIf="
|
|
||||||
SelectUserDialogType.NewChat === SelectUserDialogType.NewChat;
|
|
||||||
then newchatcount;
|
|
||||||
else defaultcount
|
|
||||||
"
|
|
||||||
></ng-container>
|
|
||||||
<ng-template #newchatcount>
|
|
||||||
<span [ngClass]="selectedUserList.length >= 300 ? 'text-warn-color' : ''">
|
|
||||||
{{ selectedUserList.length }} / 300
|
|
||||||
<!-- {{ environment.productConfig.CommonSetting.maxChatRoomUser - 1 }} -->
|
|
||||||
<!-- {{ 'common.units.persons' | translate }} -->
|
|
||||||
</span>
|
|
||||||
<span
|
|
||||||
class="text-warn-color"
|
|
||||||
style="float: right;"
|
|
||||||
*ngIf="selectedUserList.length >= 300"
|
|
||||||
>
|
|
||||||
<!-- ({{
|
|
||||||
'chat.errors.maxCountOfRoomMemberWith'
|
|
||||||
| translate
|
|
||||||
: {
|
|
||||||
maxCount:
|
|
||||||
environment.productConfig.CommonSetting.maxChatRoomUser - 1
|
|
||||||
}
|
|
||||||
}}) -->
|
|
||||||
</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template #defaultcount>
|
|
||||||
<span>
|
|
||||||
{{ selectedUserList.length }}
|
|
||||||
<!-- {{ 'common.units.persons' | translate }} -->
|
|
||||||
</span>
|
|
||||||
</ng-template>
|
|
||||||
</ng-template>
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ import {
|
||||||
import { UserInfo as RoomUserInfo } from '@ucap/protocol-room';
|
import { UserInfo as RoomUserInfo } from '@ucap/protocol-room';
|
||||||
import { LoginResponse } from '@ucap/protocol-authentication';
|
import { LoginResponse } from '@ucap/protocol-authentication';
|
||||||
import { LoginSelector } from '@ucap/ng-store-authentication';
|
import { LoginSelector } from '@ucap/ng-store-authentication';
|
||||||
|
import { SearchData } from '@app/ucap/organization/models/search-data';
|
||||||
|
|
||||||
export type UserInfoTypes =
|
export type UserInfoTypes =
|
||||||
| UserInfo
|
| UserInfo
|
||||||
|
@ -61,16 +62,22 @@ export class SelectUserSectionComponent implements OnInit, OnDestroy {
|
||||||
existUsers: UserInfoTypes[];
|
existUsers: UserInfoTypes[];
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
set checkable(check: boolean) {
|
isSelectionOff = true;
|
||||||
this._checkable = check;
|
|
||||||
}
|
@Input()
|
||||||
get checkable(): boolean {
|
checkable = false;
|
||||||
return this._checkable;
|
|
||||||
}
|
|
||||||
_checkable = false;
|
|
||||||
|
|
||||||
@Output()
|
@Output()
|
||||||
changeUserList = new EventEmitter<UserInfoTypes[]>();
|
toggleCheckUser: EventEmitter<{
|
||||||
|
checked: boolean;
|
||||||
|
userInfo: UserInfoSS;
|
||||||
|
}> = new EventEmitter();
|
||||||
|
|
||||||
|
@Output()
|
||||||
|
toggleCheckGroup: EventEmitter<{
|
||||||
|
isChecked: boolean;
|
||||||
|
groupBuddyList: { group: GroupDetailData; buddyList: UserInfo[] };
|
||||||
|
}> = new EventEmitter();
|
||||||
|
|
||||||
@Output()
|
@Output()
|
||||||
cancel = new EventEmitter();
|
cancel = new EventEmitter();
|
||||||
|
@ -78,11 +85,23 @@ export class SelectUserSectionComponent implements OnInit, OnDestroy {
|
||||||
@Output()
|
@Output()
|
||||||
confirm = new EventEmitter();
|
confirm = new EventEmitter();
|
||||||
|
|
||||||
|
set companySearchData(searchData: SearchData) {
|
||||||
|
this._companySearchData = searchData;
|
||||||
|
|
||||||
|
this.onChangedCompanySearch();
|
||||||
|
}
|
||||||
|
get companySearchData() {
|
||||||
|
return this._companySearchData;
|
||||||
|
}
|
||||||
|
// tslint:disable-next-line: variable-name
|
||||||
|
_companySearchData: SearchData;
|
||||||
|
|
||||||
isSearch = false;
|
isSearch = false;
|
||||||
searchWord: string;
|
searchWord: string;
|
||||||
|
|
||||||
private ngOnDestroySubject = new Subject<boolean>();
|
private ngOnDestroySubject = new Subject<boolean>();
|
||||||
|
|
||||||
|
@Input()
|
||||||
selectedUserList: UserInfoTypes[] = [];
|
selectedUserList: UserInfoTypes[] = [];
|
||||||
searchUserInfos: UserInfoSS[] = [];
|
searchUserInfos: UserInfoSS[] = [];
|
||||||
|
|
||||||
|
@ -113,20 +132,15 @@ export class SelectUserSectionComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onCheckUser(params: { isChecked: boolean; userInfo: UserInfoTypes }) {
|
onToggleCheckGroup(params: {
|
||||||
console.log(params);
|
isChecked: boolean;
|
||||||
if (
|
groupBuddyList: { group: GroupDetailData; buddyList: UserInfo[] };
|
||||||
this.selectedUserList.filter((user) => user.seq === params.userInfo.seq)
|
}) {
|
||||||
.length === 0
|
this.toggleCheckGroup.emit(params);
|
||||||
) {
|
|
||||||
this.selectedUserList = [...this.selectedUserList, params.userInfo];
|
|
||||||
} else {
|
|
||||||
this.selectedUserList = this.selectedUserList.filter(
|
|
||||||
(item) => item.seq !== params.userInfo.seq
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.changeUserList.emit(this.selectedUserList);
|
onToggleCheckUser(data: { checked: boolean; userInfo: UserInfoSS }) {
|
||||||
|
this.toggleCheckUser.emit(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
getCheckedUser(userInfo: UserInfoTypes) {
|
getCheckedUser(userInfo: UserInfoTypes) {
|
||||||
|
@ -139,96 +153,8 @@ export class SelectUserSectionComponent implements OnInit, OnDestroy {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
onCheckGroup(params: {
|
onChangedCompanySearch() {
|
||||||
isChecked: boolean;
|
|
||||||
groupBuddyList: { group: GroupDetailData; buddyList: UserInfo[] };
|
|
||||||
}) {
|
|
||||||
if (params.isChecked) {
|
|
||||||
params.groupBuddyList.buddyList.forEach((item) => {
|
|
||||||
if (
|
|
||||||
this.selectedUserList.filter((user) => user.seq === item.seq)
|
|
||||||
.length === 0
|
|
||||||
) {
|
|
||||||
this.selectedUserList = [...this.selectedUserList, item];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.selectedUserList = this.selectedUserList.filter(
|
|
||||||
(item) =>
|
|
||||||
params.groupBuddyList.buddyList.filter((del) => del.seq === item.seq)
|
|
||||||
.length === 0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
this.changeDetectorRef.markForCheck();
|
|
||||||
}
|
|
||||||
getSelectedUserList(): any[] {
|
|
||||||
return this.selectedUserList;
|
|
||||||
}
|
|
||||||
|
|
||||||
getChipsRemoveYn(userInfo: UserInfoTypes) {
|
|
||||||
if (!!this.existUsers && this.existUsers.length > 0) {
|
|
||||||
return !(
|
|
||||||
this.existUsers.filter((user) => user.seq === userInfo.seq).length > 0
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onClickDeleteUser(userInfo: UserInfoTypes) {
|
|
||||||
this.selectedUserList = this.selectedUserList.filter(
|
|
||||||
(item) => item.seq !== userInfo.seq
|
|
||||||
);
|
|
||||||
this.changeDetectorRef.markForCheck();
|
|
||||||
}
|
|
||||||
|
|
||||||
onChanged(data: { companyCode: string; searchWord: string }) {
|
|
||||||
this.isSearch = true;
|
this.isSearch = true;
|
||||||
this.searchWord = data.searchWord;
|
|
||||||
|
|
||||||
const searchUserInfos: UserInfoSS[] = [];
|
|
||||||
|
|
||||||
this.queryProtocolService
|
|
||||||
.deptUser({
|
|
||||||
divCd: 'GRP',
|
|
||||||
companyCode: data.companyCode,
|
|
||||||
searchRange: DeptSearchType.All,
|
|
||||||
search: data.searchWord,
|
|
||||||
senderCompanyCode: this.loginRes.userInfo.companyCode,
|
|
||||||
senderEmployeeType: this.loginRes.userInfo.employeeType
|
|
||||||
})
|
|
||||||
.pipe(
|
|
||||||
map((resObj) => {
|
|
||||||
const userInfos = resObj.userInfos;
|
|
||||||
|
|
||||||
searchUserInfos.push(...userInfos);
|
|
||||||
// 검색 결과 처리.
|
|
||||||
this.searchUserInfos = searchUserInfos.sort((a, b) =>
|
|
||||||
a.name < b.name ? -1 : a.name > b.name ? 1 : 0
|
|
||||||
);
|
|
||||||
// this.searchProcessing = false;
|
|
||||||
|
|
||||||
// 검색 결과에 따른 프레즌스 조회.
|
|
||||||
const userSeqList: number[] = [];
|
|
||||||
this.searchUserInfos.map((user) =>
|
|
||||||
userSeqList.push(Number(user.seq))
|
|
||||||
);
|
|
||||||
this.changeDetectorRef.markForCheck();
|
|
||||||
if (userSeqList.length > 0) {
|
|
||||||
// this.store.dispatch(
|
|
||||||
// StatusStore.bulkInfo({
|
|
||||||
// divCd: 'groupSrch',
|
|
||||||
// userSeqs: userSeqList
|
|
||||||
// })
|
|
||||||
// );
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
catchError((error) => {
|
|
||||||
// this.searchProcessing = false;
|
|
||||||
return of(error);
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.subscribe();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onCanceled() {
|
onCanceled() {
|
||||||
|
|
|
@ -43,12 +43,25 @@
|
||||||
</mat-step>
|
</mat-step>
|
||||||
<mat-step label="Step 1">
|
<mat-step label="Step 1">
|
||||||
<app-group-select-user
|
<app-group-select-user
|
||||||
|
style="height: 500px;"
|
||||||
[isDialog]="true"
|
[isDialog]="true"
|
||||||
[checkable]="true"
|
[checkable]="true"
|
||||||
(changeUserList)="onChangeUserList($event)"
|
[selectedUserList]="selectedUserList"
|
||||||
|
(toggleCheckUser)="onChangeUserList($event)"
|
||||||
|
(toggleCheckGroup)="onChangeGroupList($event)"
|
||||||
></app-group-select-user>
|
></app-group-select-user>
|
||||||
</mat-step>
|
</mat-step>
|
||||||
</mat-horizontal-stepper>
|
</mat-horizontal-stepper>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<ucap-organization-profile-selection-01
|
||||||
|
[userInfoList]="selectedUserList"
|
||||||
|
[removableFor]="removableForSelection"
|
||||||
|
[colorFor]="colorForSelection"
|
||||||
|
(removed)="onRemovedProfileSelection($event)"
|
||||||
|
>
|
||||||
|
</ucap-organization-profile-selection-01>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div appLayoutsDefaultDialog="action">
|
<div appLayoutsDefaultDialog="action">
|
||||||
<button mat-button (click)="onCancel(stepper)">취소</button>
|
<button mat-button (click)="onCancel(stepper)">취소</button>
|
||||||
|
|
|
@ -147,7 +147,63 @@ export class CreateDialogComponent implements OnInit, OnDestroy {
|
||||||
this.inputForm.get('groupName').markAsTouched();
|
this.inputForm.get('groupName').markAsTouched();
|
||||||
}
|
}
|
||||||
|
|
||||||
onChangeUserList(selectedUserList: UserInfoTypes[]) {
|
onChangeUserList(data: { checked: boolean; userInfo: UserInfoSS }) {
|
||||||
this.selectedUserList = selectedUserList;
|
const i = this.selectedUserList.findIndex(
|
||||||
|
(u) => u.seq === data.userInfo.seq
|
||||||
|
);
|
||||||
|
|
||||||
|
if (data.checked) {
|
||||||
|
if (-1 === i) {
|
||||||
|
this.selectedUserList = [...this.selectedUserList, data.userInfo];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (-1 < i) {
|
||||||
|
this.selectedUserList = this.selectedUserList.filter(
|
||||||
|
(u) => u.seq !== data.userInfo.seq
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeGroupList(params: {
|
||||||
|
isChecked: boolean;
|
||||||
|
groupBuddyList: { group: GroupDetailData; buddyList: UserInfo[] };
|
||||||
|
}) {
|
||||||
|
if (params.isChecked) {
|
||||||
|
params.groupBuddyList.buddyList.forEach((item) => {
|
||||||
|
if (
|
||||||
|
this.selectedUserList.filter((user) => user.seq === item.seq)
|
||||||
|
.length === 0
|
||||||
|
) {
|
||||||
|
this.selectedUserList = [...this.selectedUserList, item];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.selectedUserList = this.selectedUserList.filter(
|
||||||
|
(item) =>
|
||||||
|
params.groupBuddyList.buddyList.filter((del) => del.seq === item.seq)
|
||||||
|
.length === 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onRemovedProfileSelection(userInfo: UserInfo) {
|
||||||
|
const i = this.selectedUserList.findIndex(
|
||||||
|
(u) => (u.seq as any) === (userInfo.seq as any)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (-1 < i) {
|
||||||
|
this.selectedUserList = this.selectedUserList.filter(
|
||||||
|
(u) => (u.seq as any) !== (userInfo.seq as any)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removableForSelection = (userInfo: UserInfo) => {
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
colorForSelection = (userInfo: UserInfo) => {
|
||||||
|
return 'accent';
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
<div class="dialog-container">
|
||||||
|
<app-layouts-default-dialog
|
||||||
|
[disableClose]="false"
|
||||||
|
(closed)="onClosed($event)"
|
||||||
|
>
|
||||||
|
<div appLayoutsDefaultDialog="header">
|
||||||
|
{{ data.title }}
|
||||||
|
</div>
|
||||||
|
<div class="dialog-body" appLayoutsDefaultDialog="body">
|
||||||
|
<app-sections-select-group
|
||||||
|
[isMemberMove]="data.type"
|
||||||
|
[isDialog]="true"
|
||||||
|
[checkable]="true"
|
||||||
|
[curGroup]="data.group"
|
||||||
|
(changeUserList)="onChangeUserList($event)"
|
||||||
|
(changeGroupList)="onChangeGroupList($event)"
|
||||||
|
(changeGroupName)="onChangeGroupName($event)"
|
||||||
|
></app-sections-select-group>
|
||||||
|
<div>
|
||||||
|
<ucap-organization-profile-selection-01
|
||||||
|
[userInfoList]="selectedUserList"
|
||||||
|
[removableFor]="removableForSelection"
|
||||||
|
[colorFor]="colorForSelection"
|
||||||
|
(removed)="onRemovedProfileSelection($event)"
|
||||||
|
>
|
||||||
|
</ucap-organization-profile-selection-01>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div appLayoutsDefaultDialog="action">
|
||||||
|
<button mat-button (click)="onClosed($event)">취소</button>
|
||||||
|
<button mat-button (click)="onConfirm()">
|
||||||
|
완료
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</app-layouts-default-dialog>
|
||||||
|
</div>
|
|
@ -0,0 +1,9 @@
|
||||||
|
.dialog-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.dialog-body {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { By } from '@angular/platform-browser';
|
||||||
|
import { DebugElement } from '@angular/core';
|
||||||
|
|
||||||
|
import { EditUserDialogComponent } from './edit-user.dialog.component';
|
||||||
|
|
||||||
|
describe('ucap::ui-organization::EditUserDialogComponent', () => {
|
||||||
|
let component: EditUserDialogComponent;
|
||||||
|
let fixture: ComponentFixture<EditUserDialogComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [EditUserDialogComponent]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(EditUserDialogComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
149
src/app/sections/group/dialogs/edit-user.dialog.component.ts
Normal file
149
src/app/sections/group/dialogs/edit-user.dialog.component.ts
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
import { Subject } from 'rxjs';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Component,
|
||||||
|
OnInit,
|
||||||
|
OnDestroy,
|
||||||
|
ChangeDetectionStrategy,
|
||||||
|
ChangeDetectorRef,
|
||||||
|
Inject,
|
||||||
|
Input
|
||||||
|
} from '@angular/core';
|
||||||
|
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
|
||||||
|
import {
|
||||||
|
MatDialogRef,
|
||||||
|
MAT_DIALOG_DATA,
|
||||||
|
MatDialog
|
||||||
|
} from '@angular/material/dialog';
|
||||||
|
|
||||||
|
import { UserInfo, GroupDetailData } from '@ucap/protocol-sync';
|
||||||
|
import { UserInfoSS, UserInfoF, UserInfoDN } from '@ucap/protocol-query';
|
||||||
|
import { UserInfo as RoomUserInfo } from '@ucap/protocol-room';
|
||||||
|
import { I18nService } from '@ucap/ng-i18n';
|
||||||
|
|
||||||
|
import { SelectUserDialogType, GroupUserDialaogType } from '@app/types';
|
||||||
|
|
||||||
|
export type UserInfoTypes =
|
||||||
|
| UserInfo
|
||||||
|
| UserInfoSS
|
||||||
|
| UserInfoF
|
||||||
|
| UserInfoDN
|
||||||
|
| RoomUserInfo;
|
||||||
|
|
||||||
|
export interface EditUserDialogData {
|
||||||
|
title: string;
|
||||||
|
type: GroupUserDialaogType;
|
||||||
|
group: GroupDetailData;
|
||||||
|
userInfo: UserInfoTypes;
|
||||||
|
}
|
||||||
|
export interface EditUserDialogResult {
|
||||||
|
type: GroupUserDialaogType;
|
||||||
|
groupName: string;
|
||||||
|
group: GroupDetailData;
|
||||||
|
selelctUserList?: UserInfoTypes[];
|
||||||
|
selectGroupList?: GroupDetailData[];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-dialog-edit-user',
|
||||||
|
templateUrl: './edit-user.dialog.component.html',
|
||||||
|
styleUrls: ['./edit-user.dialog.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
|
})
|
||||||
|
export class EditUserDialogComponent implements OnInit, OnDestroy {
|
||||||
|
constructor(
|
||||||
|
public dialogRef: MatDialogRef<EditUserDialogData, EditUserDialogResult>,
|
||||||
|
@Inject(MAT_DIALOG_DATA) public data: EditUserDialogData,
|
||||||
|
private changeDetectorRef: ChangeDetectorRef,
|
||||||
|
private store: Store<any>,
|
||||||
|
private i18nService: I18nService,
|
||||||
|
public dialog: MatDialog
|
||||||
|
) {}
|
||||||
|
|
||||||
|
private ngOnDestroySubject: Subject<void>;
|
||||||
|
|
||||||
|
currentType: GroupUserDialaogType;
|
||||||
|
selectedUserList: UserInfoTypes[] = [];
|
||||||
|
selectedGroupList: GroupDetailData[] = [];
|
||||||
|
groupName = '';
|
||||||
|
SelectUserDialogType = SelectUserDialogType;
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.ngOnDestroySubject = new Subject();
|
||||||
|
|
||||||
|
this.selectedUserList.push(this.data.userInfo);
|
||||||
|
this.currentType = this.data.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
if (!!this.ngOnDestroySubject) {
|
||||||
|
this.ngOnDestroySubject.complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onClosed(event: MouseEvent): void {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
onConfirm() {
|
||||||
|
if (!!this.groupName && this.groupName.trim().localeCompare('') !== 0) {
|
||||||
|
this.currentType = GroupUserDialaogType.Create;
|
||||||
|
} else {
|
||||||
|
this.groupName = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dialogRef.close({
|
||||||
|
type: this.currentType,
|
||||||
|
groupName: this.groupName,
|
||||||
|
group: this.data.group,
|
||||||
|
selelctUserList: this.selectedUserList,
|
||||||
|
selectGroupList: this.selectedGroupList
|
||||||
|
});
|
||||||
|
}
|
||||||
|
onChangeUserList(data: { checked: boolean; userInfo: UserInfoSS }) {
|
||||||
|
const i = this.selectedUserList.findIndex(
|
||||||
|
(u) => u.seq === data.userInfo.seq
|
||||||
|
);
|
||||||
|
|
||||||
|
if (data.checked) {
|
||||||
|
if (-1 === i) {
|
||||||
|
this.selectedUserList = [...this.selectedUserList, data.userInfo];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (-1 < i) {
|
||||||
|
this.selectedUserList = this.selectedUserList.filter(
|
||||||
|
(u) => u.seq !== data.userInfo.seq
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeGroupList(selectedGroupList: GroupDetailData[]) {
|
||||||
|
this.selectedGroupList = selectedGroupList;
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeGroupName(name: string) {
|
||||||
|
this.groupName = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
onRemovedProfileSelection(userInfo: UserInfo) {
|
||||||
|
const i = this.selectedUserList.findIndex(
|
||||||
|
(u) => (u.seq as any) === (userInfo.seq as any)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (-1 < i) {
|
||||||
|
this.selectedUserList = this.selectedUserList.filter(
|
||||||
|
(u) => (u.seq as any) !== (userInfo.seq as any)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removableForSelection = (userInfo: UserInfo) => {
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
colorForSelection = (userInfo: UserInfo) => {
|
||||||
|
return 'accent';
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,4 +1,11 @@
|
||||||
import { CreateDialogComponent } from './create.dialog.component';
|
import { CreateDialogComponent } from './create.dialog.component';
|
||||||
import { EditInlineInputDialogComponent } from './edit-inline-input.dialog.component';
|
import { EditInlineInputDialogComponent } from './edit-inline-input.dialog.component';
|
||||||
|
import { ManageDialogComponent } from './manage.dialog.component';
|
||||||
|
import { EditUserDialogComponent } from './edit-user.dialog.component';
|
||||||
|
|
||||||
export const DIALOGS = [CreateDialogComponent, EditInlineInputDialogComponent];
|
export const DIALOGS = [
|
||||||
|
CreateDialogComponent,
|
||||||
|
EditInlineInputDialogComponent,
|
||||||
|
ManageDialogComponent,
|
||||||
|
EditUserDialogComponent
|
||||||
|
];
|
||||||
|
|
|
@ -12,28 +12,68 @@
|
||||||
#stepper
|
#stepper
|
||||||
[selectedIndex]="currentStep"
|
[selectedIndex]="currentStep"
|
||||||
>
|
>
|
||||||
<mat-step label="Step 1"> </mat-step>
|
|
||||||
<mat-step label="Step 1">
|
<mat-step label="Step 1">
|
||||||
<app-group-select-user
|
<div>
|
||||||
|
<div>
|
||||||
|
{{ data.groupBuddyList.group.name }}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
mat-button
|
||||||
|
(click)="onAdd(stepper)"
|
||||||
|
aria-label="대화상대 추가"
|
||||||
|
>
|
||||||
|
<mat-icon>add</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<app-group-profile-list-item-02
|
||||||
|
*ngFor="let userInfo of this.data.groupBuddyList.buddyList"
|
||||||
|
[userInfo]="userInfo"
|
||||||
[isDialog]="true"
|
[isDialog]="true"
|
||||||
|
[checked]="getCheckedUser(userInfo)"
|
||||||
[checkable]="true"
|
[checkable]="true"
|
||||||
(changeUserList)="onChangeUserList($event)"
|
(changeCheckUser)="onToggleCheck($event)"
|
||||||
></app-group-select-user>
|
></app-group-profile-list-item-02>
|
||||||
|
</div>
|
||||||
|
</mat-step>
|
||||||
|
<mat-step label="Step 2">
|
||||||
|
<ng-template #dialogContainer></ng-template>
|
||||||
</mat-step>
|
</mat-step>
|
||||||
</mat-horizontal-stepper>
|
</mat-horizontal-stepper>
|
||||||
|
<div>
|
||||||
|
<ucap-organization-profile-selection-01
|
||||||
|
[userInfoList]="selectedUserList"
|
||||||
|
[removableFor]="removableForSelection"
|
||||||
|
[colorFor]="colorForSelection"
|
||||||
|
(removed)="onRemovedProfileSelection($event)"
|
||||||
|
>
|
||||||
|
</ucap-organization-profile-selection-01>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div appLayoutsDefaultDialog="action">
|
<div appLayoutsDefaultDialog="action">
|
||||||
|
<div *ngIf="currentStep === 0">
|
||||||
<button mat-button (click)="onDelete(stepper)">삭제</button>
|
<button mat-button (click)="onDelete(stepper)">삭제</button>
|
||||||
|
<button
|
||||||
|
mat-button
|
||||||
|
(click)="onUpdateMember(stepper, GroupUserDialaogType.Copy)"
|
||||||
|
>
|
||||||
|
그룹복사
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
mat-button
|
||||||
|
(click)="onUpdateMember(stepper, GroupUserDialaogType.Move)"
|
||||||
|
>
|
||||||
|
그룹이동
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="currentStep > 0">
|
||||||
|
<button mat-button (click)="onCnacel(stepper)">취소</button>
|
||||||
<button mat-button (click)="onConfirm(stepper)">
|
<button mat-button (click)="onConfirm(stepper)">
|
||||||
완료
|
완료
|
||||||
</button>
|
</button>
|
||||||
<button
|
</div>
|
||||||
*ngIf="currentStep < 1"
|
|
||||||
mat-button
|
|
||||||
(click)="onCompleteConfirm(stepper)"
|
|
||||||
>
|
|
||||||
그룹지정후 완료
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</app-layouts-default-dialog>
|
</app-layouts-default-dialog>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Subject } from 'rxjs';
|
import { Subject, of } from 'rxjs';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Component,
|
Component,
|
||||||
|
@ -7,7 +7,11 @@ import {
|
||||||
ChangeDetectionStrategy,
|
ChangeDetectionStrategy,
|
||||||
ChangeDetectorRef,
|
ChangeDetectorRef,
|
||||||
Inject,
|
Inject,
|
||||||
Input
|
Input,
|
||||||
|
ComponentFactoryResolver,
|
||||||
|
ViewChild,
|
||||||
|
ViewContainerRef,
|
||||||
|
ComponentRef
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
|
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
|
@ -28,8 +32,15 @@ import { GroupActions } from '@ucap/ng-store-group';
|
||||||
import {
|
import {
|
||||||
AlertDialogComponent,
|
AlertDialogComponent,
|
||||||
AlertDialogData,
|
AlertDialogData,
|
||||||
AlertDialogResult
|
AlertDialogResult,
|
||||||
|
ConfirmDialogComponent,
|
||||||
|
ConfirmDialogResult,
|
||||||
|
ConfirmDialogData
|
||||||
} from '@ucap/ng-ui';
|
} from '@ucap/ng-ui';
|
||||||
|
import { SelectUserSectionComponent } from '../components/select-user.section.component';
|
||||||
|
import { take, map, catchError } from 'rxjs/operators';
|
||||||
|
import { SelectGroupSectionComponent } from '../components/select-group.section.component';
|
||||||
|
import { SelectUserDialogType, GroupUserDialaogType } from '@app/types';
|
||||||
|
|
||||||
export type UserInfoTypes =
|
export type UserInfoTypes =
|
||||||
| UserInfo
|
| UserInfo
|
||||||
|
@ -40,8 +51,15 @@ export type UserInfoTypes =
|
||||||
|
|
||||||
export interface ManageDialogData {
|
export interface ManageDialogData {
|
||||||
title: string;
|
title: string;
|
||||||
|
groupBuddyList?: { group: GroupDetailData; buddyList: UserInfo[] };
|
||||||
|
}
|
||||||
|
export interface ManageDialogResult {
|
||||||
|
type: GroupUserDialaogType;
|
||||||
|
groupName: string;
|
||||||
|
group?: GroupDetailData;
|
||||||
|
selelctUserList?: UserInfoTypes[];
|
||||||
|
selectGroupList?: GroupDetailData[];
|
||||||
}
|
}
|
||||||
export interface ManageDialogResult {}
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-dialog-group-manage',
|
selector: 'app-dialog-group-manage',
|
||||||
|
@ -57,16 +75,29 @@ export class ManageDialogComponent implements OnInit, OnDestroy {
|
||||||
private store: Store<any>,
|
private store: Store<any>,
|
||||||
private formBuilder: FormBuilder,
|
private formBuilder: FormBuilder,
|
||||||
private i18nService: I18nService,
|
private i18nService: I18nService,
|
||||||
public dialog: MatDialog
|
public dialog: MatDialog,
|
||||||
|
private cfResolver: ComponentFactoryResolver
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
private ngOnDestroySubject: Subject<void>;
|
@ViewChild('dialogContainer', { static: true, read: ViewContainerRef })
|
||||||
currentStep = 0;
|
dialogContainer: ViewContainerRef;
|
||||||
|
|
||||||
|
componentRef: ComponentRef<any>;
|
||||||
|
private ngOnDestroySubject: Subject<void>;
|
||||||
|
currentType: GroupUserDialaogType;
|
||||||
|
SelectUserDialogType = SelectUserDialogType;
|
||||||
|
GroupUserDialaogType = GroupUserDialaogType;
|
||||||
|
|
||||||
|
currentStep = 0;
|
||||||
|
groupName = '';
|
||||||
|
|
||||||
|
delteUserList: UserInfoTypes[] = [];
|
||||||
selectedUserList: UserInfoTypes[] = [];
|
selectedUserList: UserInfoTypes[] = [];
|
||||||
|
selectedGroupList: GroupDetailData[] = [];
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.ngOnDestroySubject = new Subject();
|
this.ngOnDestroySubject = new Subject();
|
||||||
|
// this.selectedUserList = this.data.groupBuddyList.buddyList;
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
|
@ -80,14 +111,111 @@ export class ManageDialogComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
onDelete(stepper: MatStepper) {
|
onDelete(stepper: MatStepper) {
|
||||||
|
if (
|
||||||
|
!!this.delteUserList &&
|
||||||
|
this.delteUserList.length > 0 &&
|
||||||
|
this.currentStep === 0
|
||||||
|
) {
|
||||||
|
let titleStr = '';
|
||||||
|
this.delteUserList.forEach((user, idx) => {
|
||||||
|
let userTitle = user.name + ' ' + user.grade;
|
||||||
|
if (idx < this.delteUserList.length) {
|
||||||
|
userTitle = userTitle + ', ';
|
||||||
|
}
|
||||||
|
titleStr = titleStr.concat('', userTitle);
|
||||||
|
});
|
||||||
|
const dialogRef = this.dialog.open<
|
||||||
|
ConfirmDialogComponent,
|
||||||
|
ConfirmDialogData,
|
||||||
|
ConfirmDialogResult
|
||||||
|
>(ConfirmDialogComponent, {
|
||||||
|
data: {
|
||||||
|
title: '동료 삭제',
|
||||||
|
html: titleStr + '을 삭제하시겠습니까?'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dialogRef
|
||||||
|
.afterClosed()
|
||||||
|
.pipe(
|
||||||
|
take(1),
|
||||||
|
map((result) => {
|
||||||
|
if (!!result && result.choice) {
|
||||||
|
const trgtUserSeq: string[] = [];
|
||||||
|
|
||||||
|
this.delteUserList.forEach((userIfno) => {
|
||||||
|
const tempSeq = this.data.groupBuddyList.group.userSeqs.filter(
|
||||||
|
(seq) => seq === userIfno.seq
|
||||||
|
);
|
||||||
|
|
||||||
|
trgtUserSeq.push(tempSeq[0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(trgtUserSeq);
|
||||||
|
|
||||||
|
this.store.dispatch(
|
||||||
|
GroupActions.updateMember({
|
||||||
|
targetGroup: this.data.groupBuddyList.group,
|
||||||
|
targetUserSeqs: trgtUserSeq
|
||||||
|
})
|
||||||
|
);
|
||||||
this.dialogRef.close();
|
this.dialogRef.close();
|
||||||
}
|
}
|
||||||
onCopy(stepper: MatStepper) {
|
}),
|
||||||
this.dialogRef.close();
|
catchError((err) => {
|
||||||
|
return of(err);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.subscribe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onUpdateMember(stepper: MatStepper, type: GroupUserDialaogType) {
|
||||||
|
this.dialogContainer.clear();
|
||||||
|
this.currentType = type;
|
||||||
|
const isMemberMove = type === GroupUserDialaogType.Copy ? false : true;
|
||||||
|
// const title = type === GroupUserDialaogType.Copy ? '멤버 복사' : '멤버 이동';
|
||||||
|
|
||||||
|
const factory = this.cfResolver.resolveComponentFactory(
|
||||||
|
SelectGroupSectionComponent
|
||||||
|
);
|
||||||
|
|
||||||
|
this.componentRef = this.dialogContainer.createComponent(factory);
|
||||||
|
const cpInstance = this.componentRef.instance;
|
||||||
|
// cpInstance.title = title;
|
||||||
|
cpInstance.isMemberMove = isMemberMove;
|
||||||
|
cpInstance.isDialog = true;
|
||||||
|
cpInstance.checkable = true;
|
||||||
|
cpInstance.curGroup = this.data.groupBuddyList.group;
|
||||||
|
cpInstance.changeUserList.subscribe((val) => {
|
||||||
|
this.selectedUserList = val;
|
||||||
|
});
|
||||||
|
cpInstance.changeGroupList.subscribe((groupList) => {
|
||||||
|
this.selectedGroupList = groupList;
|
||||||
|
});
|
||||||
|
cpInstance.changeGroupName.subscribe((groupName) => {
|
||||||
|
this.groupName = groupName;
|
||||||
|
});
|
||||||
|
this.currentStep++;
|
||||||
|
stepper.next();
|
||||||
}
|
}
|
||||||
onMove(stepper: MatStepper) {}
|
|
||||||
|
|
||||||
onAdd(stepper: MatStepper) {
|
onAdd(stepper: MatStepper) {
|
||||||
|
this.dialogContainer.clear();
|
||||||
|
this.currentType = GroupUserDialaogType.Add;
|
||||||
|
// this.selectedUserList = this.data.groupBuddyList.buddyList;
|
||||||
|
|
||||||
|
const factory = this.cfResolver.resolveComponentFactory(
|
||||||
|
SelectUserSectionComponent
|
||||||
|
);
|
||||||
|
|
||||||
|
this.componentRef = this.dialogContainer.createComponent(factory);
|
||||||
|
const cpInstance = this.componentRef.instance;
|
||||||
|
cpInstance.isDialog = true;
|
||||||
|
cpInstance.checkable = true;
|
||||||
|
cpInstance.selectedUserList = this.data.groupBuddyList.buddyList;
|
||||||
|
cpInstance.isSelectionOff = false;
|
||||||
|
cpInstance.changeUserList.subscribe((val) => {
|
||||||
|
this.selectedUserList = val;
|
||||||
|
});
|
||||||
this.currentStep++;
|
this.currentStep++;
|
||||||
stepper.next();
|
stepper.next();
|
||||||
}
|
}
|
||||||
|
@ -95,4 +223,119 @@ export class ManageDialogComponent implements OnInit, OnDestroy {
|
||||||
onChangeUserList(selectedUserList: UserInfoTypes[]) {
|
onChangeUserList(selectedUserList: UserInfoTypes[]) {
|
||||||
this.selectedUserList = selectedUserList;
|
this.selectedUserList = selectedUserList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onCnacel(stepper: MatStepper) {
|
||||||
|
if (!!this.selectedUserList && this.selectedUserList.length > 0) {
|
||||||
|
this.selectedUserList = [];
|
||||||
|
}
|
||||||
|
this.currentStep--;
|
||||||
|
stepper.previous();
|
||||||
|
}
|
||||||
|
onConfirm(stepper: MatStepper) {
|
||||||
|
switch (this.currentType) {
|
||||||
|
case GroupUserDialaogType.Add:
|
||||||
|
{
|
||||||
|
if (!!this.selectedUserList && this.selectedUserList.length > 0) {
|
||||||
|
this.doAction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GroupUserDialaogType.Copy:
|
||||||
|
case GroupUserDialaogType.Move:
|
||||||
|
{
|
||||||
|
if (!!this.selectedUserList && this.selectedUserList.length === 0) {
|
||||||
|
this.dialog.open<
|
||||||
|
AlertDialogComponent,
|
||||||
|
AlertDialogData,
|
||||||
|
AlertDialogResult
|
||||||
|
>(AlertDialogComponent, {
|
||||||
|
data: {
|
||||||
|
title: 'Error',
|
||||||
|
html: '선택된 유저가 없습니다.'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.doAction();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
doAction() {
|
||||||
|
this.dialogContainer.clear();
|
||||||
|
if (!!this.groupName && this.groupName.trim().localeCompare('') !== 0) {
|
||||||
|
this.currentType = GroupUserDialaogType.Create;
|
||||||
|
} else {
|
||||||
|
this.groupName = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dialogRef.close({
|
||||||
|
type: this.currentType,
|
||||||
|
groupName: this.groupName,
|
||||||
|
group: this.data.groupBuddyList.group,
|
||||||
|
selelctUserList: this.selectedUserList,
|
||||||
|
selectGroupList: this.selectedGroupList
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 개별 체크여부 */
|
||||||
|
getCheckedUser(userInfo: UserInfoSS) {
|
||||||
|
if (!!this.selectedUserList && this.selectedUserList.length > 0) {
|
||||||
|
return (
|
||||||
|
this.selectedUserList.filter(
|
||||||
|
(item) => (item.seq as any) === (userInfo.seq as any)
|
||||||
|
).length > 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
onToggleCheckForDelete(data: { checked: boolean; userInfo: UserInfoSS }) {
|
||||||
|
if (data.checked) {
|
||||||
|
this.delteUserList.push(data.userInfo);
|
||||||
|
} else {
|
||||||
|
const index = this.delteUserList.findIndex(
|
||||||
|
(userInfo) => userInfo.seq === data.userInfo.seq
|
||||||
|
);
|
||||||
|
if (index > -1) {
|
||||||
|
this.delteUserList.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.onToggleCheck(data);
|
||||||
|
}
|
||||||
|
onToggleCheck(data: { checked: boolean; userInfo: UserInfoSS }) {
|
||||||
|
if (data.checked) {
|
||||||
|
this.selectedUserList.push(data.userInfo);
|
||||||
|
} else {
|
||||||
|
const index = this.selectedUserList.findIndex(
|
||||||
|
(userInfo) => userInfo.seq === data.userInfo.seq
|
||||||
|
);
|
||||||
|
if (index > -1) {
|
||||||
|
this.selectedUserList.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onRemovedProfileSelection(userInfo: UserInfo) {
|
||||||
|
const i = this.selectedUserList.findIndex(
|
||||||
|
(u) => (u.seq as any) === (userInfo.seq as any)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (-1 < i) {
|
||||||
|
this.selectedUserList = this.selectedUserList.filter(
|
||||||
|
(u) => (u.seq as any) !== (userInfo.seq as any)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removableForSelection = (userInfo: UserInfo) => {
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
colorForSelection = (userInfo: UserInfo) => {
|
||||||
|
return 'accent';
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,8 +43,6 @@ import { DIALOGS } from './dialogs';
|
||||||
MatIconModule,
|
MatIconModule,
|
||||||
MatCardModule,
|
MatCardModule,
|
||||||
MatCheckboxModule,
|
MatCheckboxModule,
|
||||||
MatFormFieldModule,
|
|
||||||
MatInputModule,
|
|
||||||
MatSelectModule,
|
MatSelectModule,
|
||||||
MatTabsModule,
|
MatTabsModule,
|
||||||
MatChipsModule,
|
MatChipsModule,
|
||||||
|
|
|
@ -2,7 +2,9 @@
|
||||||
<div class="title">
|
<div class="title">
|
||||||
{{ selectedDeptInfo | ucapOrganizationTranslate: 'name'
|
{{ selectedDeptInfo | ucapOrganizationTranslate: 'name'
|
||||||
}}<strong>{{
|
}}<strong>{{
|
||||||
!!searchData.isSearch ? searchUserList.length : departmentUserList.length
|
!!searchObj.isShowSearch
|
||||||
|
? searchUserList.length
|
||||||
|
: departmentUserList.length
|
||||||
}}</strong
|
}}</strong
|
||||||
>{{ 'common.units.persons' | ucapI18n }}
|
>{{ 'common.units.persons' | ucapI18n }}
|
||||||
</div>
|
</div>
|
||||||
|
@ -27,9 +29,28 @@
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
</div>
|
</div>
|
||||||
<div class="table-body" fxFlexFill>
|
<div class="table-body" fxFlexFill>
|
||||||
<app-organization-profile-list
|
<cdk-virtual-scroll-viewport #cvsvList perfectScrollbar fxFlexFill>
|
||||||
[searchData]="searchData"
|
<ucap-organization-profile-list-item-01
|
||||||
></app-organization-profile-list>
|
*cdkVirtualFor="
|
||||||
|
let userInfo of !!searchObj.isShowSearch
|
||||||
|
? searchUserList
|
||||||
|
: departmentUserList
|
||||||
|
"
|
||||||
|
[userInfo]="userInfo"
|
||||||
|
[checkable]="loginRes?.userSeq !== userInfo.seq"
|
||||||
|
[checked]="getCheckedUser(userInfo)"
|
||||||
|
(openProfile)="onOpenProfile($event)"
|
||||||
|
(changeCheck)="onToggleUser($event)"
|
||||||
|
>
|
||||||
|
<ucap-organization-profile-image-01
|
||||||
|
ucapOrganizationProfileListItem01="profileImage"
|
||||||
|
[userInfo]="userInfo"
|
||||||
|
[profileImageRoot]="versionInfo2Res?.profileRoot"
|
||||||
|
defaultProfileImage="assets/images/ico/img_nophoto.svg"
|
||||||
|
>
|
||||||
|
</ucap-organization-profile-image-01>
|
||||||
|
</ucap-organization-profile-list-item-01>
|
||||||
|
</cdk-virtual-scroll-viewport>
|
||||||
</div>
|
</div>
|
||||||
<div class="selected-users">
|
<div class="selected-users">
|
||||||
<mat-accordion class="organization-accordion">
|
<mat-accordion class="organization-accordion">
|
||||||
|
|
|
@ -59,7 +59,26 @@ export class DepartmentUserVirtualScrollStrategy extends FixedSizeVirtualScrollS
|
||||||
})
|
})
|
||||||
export class DetailTableComponent implements OnInit, OnDestroy {
|
export class DetailTableComponent implements OnInit, OnDestroy {
|
||||||
@Input()
|
@Input()
|
||||||
searchData: any;
|
set searchObj(obj: {
|
||||||
|
isShowSearch: boolean;
|
||||||
|
companyCode: string;
|
||||||
|
searchWord: string;
|
||||||
|
}) {
|
||||||
|
this._searchObj = obj;
|
||||||
|
if (obj.isShowSearch && obj.searchWord.localeCompare('') !== 0) {
|
||||||
|
this.onOrganizationTenantSearch(obj);
|
||||||
|
} else {
|
||||||
|
this._searchObj.isShowSearch = false;
|
||||||
|
this.searchUserList = [];
|
||||||
|
this.changeDetectorRef.detectChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get searchObj() {
|
||||||
|
return this._searchObj;
|
||||||
|
}
|
||||||
|
// tslint:disable-next-line: variable-name
|
||||||
|
_searchObj: any;
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
set deptSeq(deptSeq: string) {
|
set deptSeq(deptSeq: string) {
|
||||||
|
@ -198,13 +217,59 @@ export class DetailTableComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onOrganizationTenantSearch(obj: {
|
||||||
|
isShowSearch: boolean;
|
||||||
|
companyCode: string;
|
||||||
|
searchWord: string;
|
||||||
|
}) {
|
||||||
|
this.departmentUserListProcessing = true;
|
||||||
|
|
||||||
|
this.queryProtocolService
|
||||||
|
.deptUser({
|
||||||
|
divCd: 'ORGS',
|
||||||
|
companyCode: this._searchObj.companyCode,
|
||||||
|
searchRange: DeptSearchType.All,
|
||||||
|
search: this._searchObj.searchWord,
|
||||||
|
senderCompanyCode: this.loginRes.userInfo.companyCode,
|
||||||
|
senderEmployeeType: this.loginRes.userInfo.employeeType
|
||||||
|
})
|
||||||
|
.pipe(
|
||||||
|
map((resObj) => {
|
||||||
|
// 검색 결과 처리.
|
||||||
|
this.searchUserList = resObj.userInfos.sort((a, b) =>
|
||||||
|
a.name < b.name ? -1 : a.name > b.name ? 1 : 0
|
||||||
|
);
|
||||||
|
this.changeDetectorRef.detectChanges();
|
||||||
|
this.departmentUserListProcessing = false;
|
||||||
|
|
||||||
|
// 검색 결과에 따른 프레즌스 조회.
|
||||||
|
const userSeqList: string[] = [];
|
||||||
|
this.searchUserList.map((user) => userSeqList.push(user.seq));
|
||||||
|
|
||||||
|
if (userSeqList.length > 0) {
|
||||||
|
this.store.dispatch(
|
||||||
|
PresenceActions.bulkInfo({
|
||||||
|
divCd: 'orgSrch',
|
||||||
|
userSeqs: userSeqList
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
catchError((error) => {
|
||||||
|
this.departmentUserListProcessing = false;
|
||||||
|
return of(error);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.subscribe();
|
||||||
|
}
|
||||||
|
|
||||||
/** 전체선택 체크여부 */
|
/** 전체선택 체크여부 */
|
||||||
getCheckedAllUser() {
|
getCheckedAllUser() {
|
||||||
if (!this.loginRes) {
|
if (!this.loginRes) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const compareList: UserInfoSS[] = !!this.searchData.isSearch
|
const compareList: UserInfoSS[] = !!this.searchObj.isShowSearch
|
||||||
? this.searchUserList
|
? this.searchUserList
|
||||||
: this.departmentUserList;
|
: this.departmentUserList;
|
||||||
if (
|
if (
|
||||||
|
@ -233,7 +298,7 @@ export class DetailTableComponent implements OnInit, OnDestroy {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const trgtUserList = !!this.searchData.isSearch
|
const trgtUserList = !!this.searchObj.isShowSearch
|
||||||
? this.searchUserList
|
? this.searchUserList
|
||||||
: this.departmentUserList;
|
: this.departmentUserList;
|
||||||
|
|
||||||
|
|
|
@ -1,34 +1,99 @@
|
||||||
<div class="member-list-container" fxLayout="column">
|
<div class="member-list-container" fxLayout="column">
|
||||||
<!-- search start-->
|
|
||||||
<div fxFlex="0 0 50px">
|
|
||||||
<app-organization-search-for-tenant (changed)="onChangedSearch($event)">
|
|
||||||
</app-organization-search-for-tenant>
|
|
||||||
</div>
|
|
||||||
<!-- search end-->
|
|
||||||
|
|
||||||
<!-- content table start-->
|
<!-- content table start-->
|
||||||
<div class="member-list-body" fxFlex="1 1 auto" fxLayout="column">
|
|
||||||
<div class="list-header" fxFlex="0 0 48px" fxLayout="row">
|
<div class="list-header" fxFlex="0 0 48px" fxLayout="row">
|
||||||
<div class="list-header-title" fxFlex="1 1 auto">
|
<div class="list-header-title" fxFlex="1 1 auto">
|
||||||
<h5>아키텍처솔루션팀 <strong>20</strong>명</h5>
|
<h5>
|
||||||
|
<ng-container *ngIf="!!selectedDeptInfo">
|
||||||
|
{{ selectedDeptInfo | ucapOrganizationTranslate: 'name' }}
|
||||||
|
</ng-container>
|
||||||
|
<ng-container *ngIf="!!selectedCompanyInfo">
|
||||||
|
{{ selectedCompanyInfo.companyName }}
|
||||||
|
</ng-container>
|
||||||
|
<strong>{{ searchedProfileLength }}</strong
|
||||||
|
>명
|
||||||
|
</h5>
|
||||||
</div>
|
</div>
|
||||||
<div class="list-header-toolbox" fxFlex="0 0 100px">
|
<div class="list-header-toolbox" fxFlex="0 0 100px">
|
||||||
이름
|
이름
|
||||||
<mat-icon matSuffix class="selet-ico-obj" matRipple unbounded="true">
|
<button mat-icon-button aria-label="icon" (click)="onClickToggleSort()">
|
||||||
format_line_spacing
|
<mat-icon>format_line_spacing</mat-icon>
|
||||||
</mat-icon>
|
</button>
|
||||||
|
|
||||||
<mat-checkbox
|
<mat-checkbox
|
||||||
class="subtitle-chk-box"
|
class="subtitle-chk-box"
|
||||||
#checkboxAll
|
#checkboxAll
|
||||||
(click)="$event.stopPropagation()"
|
(change)="onChangeSelectAll($event)"
|
||||||
>
|
>
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div fxFlex="1 1 auto" fxLayout="column">
|
||||||
<div fxFlex="1 1 auto">
|
<div fxFlex="1 1 auto">
|
||||||
<app-organization-profile-list [searchData]="_searchData">
|
<app-organization-profile-list
|
||||||
|
#profileList
|
||||||
|
[searchData]="_searchData"
|
||||||
|
[selectedUser]="selectedUserInfos"
|
||||||
|
[sortOrder]="sortOrderForProfileList"
|
||||||
|
(searched)="onSearchedProfileList($event)"
|
||||||
|
(changedCheck)="onChangedCheckProfileList($event)"
|
||||||
|
>
|
||||||
</app-organization-profile-list>
|
</app-organization-profile-list>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
[style.display]="
|
||||||
|
selectedUserInfos && 0 < selectedUserInfos.length ? '' : 'none'
|
||||||
|
"
|
||||||
|
class="selected-users"
|
||||||
|
[fxFlex]="isExpanded ? '0 0 200px' : '0 0 40px'"
|
||||||
|
>
|
||||||
|
<mat-accordion class="organization-accordion">
|
||||||
|
<mat-expansion-panel
|
||||||
|
(opened)="onOpenedSelection()"
|
||||||
|
(closed)="onClosedSelection()"
|
||||||
|
>
|
||||||
|
<mat-expansion-panel-header
|
||||||
|
collapsedHeight="40px"
|
||||||
|
expandedHeight="40px"
|
||||||
|
class="organization-accordion-head"
|
||||||
|
>
|
||||||
|
<mat-panel-title class="select-user-title">
|
||||||
|
선택한 대화상대
|
||||||
|
<strong>{{
|
||||||
|
!!selectedUserInfos ? selectedUserInfos.length : 0
|
||||||
|
}}</strong>
|
||||||
|
</mat-panel-title>
|
||||||
|
<mat-panel-description> </mat-panel-description>
|
||||||
|
</mat-expansion-panel-header>
|
||||||
|
|
||||||
|
<div class="selected-user-list">
|
||||||
|
<ucap-organization-profile-selection-01
|
||||||
|
[userInfoList]="selectedUserInfos"
|
||||||
|
[removableFor]="removableForSelection"
|
||||||
|
[colorFor]="colorForSelection"
|
||||||
|
(removed)="onRemovedProfileSelection($event)"
|
||||||
|
>
|
||||||
|
</ucap-organization-profile-selection-01>
|
||||||
|
</div>
|
||||||
|
<div class="btn-box">
|
||||||
|
<button mat-stroked-button class="mat-basic">
|
||||||
|
그룹추가
|
||||||
|
</button>
|
||||||
|
<button mat-flat-button class="bg-primary-darkest">
|
||||||
|
대화
|
||||||
|
</button>
|
||||||
|
<button mat-flat-button class="bg-primary-dark">
|
||||||
|
쪽지
|
||||||
|
</button>
|
||||||
|
<button mat-flat-button class="bg-primary-dark" disabled>
|
||||||
|
전화
|
||||||
|
</button>
|
||||||
|
<button mat-flat-button class="bg-primary-dark">
|
||||||
|
화상
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
</mat-accordion>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- content table end-->
|
<!-- content table end-->
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
|
@import '~@ucap/lg-scss/mixins';
|
||||||
|
|
||||||
.member-list-container {
|
.member-list-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
.member-list-body {
|
|
||||||
align-content: space-between;
|
align-content: space-between;
|
||||||
padding: 0 30px;
|
padding: 0 30px;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
|
@ -26,9 +27,33 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.list-header-toolbox {
|
.list-header-toolbox {
|
||||||
position: absolute;
|
|
||||||
right: 0px;
|
right: 0px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.selected-users {
|
||||||
|
flex-grow: 0.8;
|
||||||
|
.organization-accordion-head {
|
||||||
|
background-color: #f1f2f6;
|
||||||
|
}
|
||||||
|
.select-user-title {
|
||||||
|
strong {
|
||||||
|
color: $lipstick;
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-user-list {
|
||||||
|
width: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-box {
|
||||||
|
margin-top: 10px;
|
||||||
|
padding-right: 8px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-content: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,89 +1,83 @@
|
||||||
|
import { Subject } from 'rxjs';
|
||||||
|
import { takeUntil } from 'rxjs/operators';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Component,
|
Component,
|
||||||
ViewChild,
|
|
||||||
OnInit,
|
OnInit,
|
||||||
ChangeDetectorRef,
|
ChangeDetectorRef,
|
||||||
Input,
|
Input,
|
||||||
OnDestroy,
|
OnDestroy,
|
||||||
ChangeDetectionStrategy
|
ChangeDetectionStrategy,
|
||||||
|
ViewChild
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { MatTableDataSource } from '@angular/material/table';
|
|
||||||
import { SelectionModel } from '@angular/cdk/collections';
|
import { select, Store } from '@ngrx/store';
|
||||||
import { MatSort } from '@angular/material/sort';
|
|
||||||
import { Subject, of } from 'rxjs';
|
import { SortOrder } from '@ucap/core';
|
||||||
import { map, takeUntil, take, catchError } from 'rxjs/operators';
|
import { LoginResponse } from '@ucap/protocol-authentication';
|
||||||
import {
|
import { DeptInfo, UserInfoSS } from '@ucap/protocol-query';
|
||||||
DeptInfo,
|
import { UserInfo } from '@ucap/protocol-sync';
|
||||||
DeptSearchType,
|
|
||||||
DeptUserRequest,
|
import { LoginSelector } from '@ucap/ng-store-authentication';
|
||||||
UserInfoSS,
|
|
||||||
AuthResponse
|
|
||||||
} from '@ucap/protocol-query';
|
|
||||||
import {
|
import {
|
||||||
DepartmentSelector,
|
DepartmentSelector,
|
||||||
PresenceActions
|
CompanySelector
|
||||||
} from '@ucap/ng-store-organization';
|
} from '@ucap/ng-store-organization';
|
||||||
import { select, Store } from '@ngrx/store';
|
|
||||||
import { QueryProtocolService } from '@ucap/ng-protocol-query';
|
|
||||||
import {
|
|
||||||
LoginSelector,
|
|
||||||
AuthorizationSelector,
|
|
||||||
ConfigurationSelector
|
|
||||||
} from '@ucap/ng-store-authentication';
|
|
||||||
import { LoginResponse } from '@ucap/protocol-authentication';
|
|
||||||
import {
|
|
||||||
FixedSizeVirtualScrollStrategy,
|
|
||||||
VIRTUAL_SCROLL_STRATEGY,
|
|
||||||
CdkVirtualScrollViewport
|
|
||||||
} from '@angular/cdk/scrolling';
|
|
||||||
import { VersionInfo2Response } from '@ucap/api-public';
|
|
||||||
import { PerfectScrollbarDirective } from 'ngx-perfect-scrollbar';
|
|
||||||
|
|
||||||
export class MemberVirtualScrollStrategy extends FixedSizeVirtualScrollStrategy {
|
import { SearchData } from '@app/ucap/organization/models/search-data';
|
||||||
constructor() {
|
import { Company } from '@ucap/api-external';
|
||||||
super(184, 150, 200);
|
import { MatCheckboxChange } from '@angular/material/checkbox';
|
||||||
}
|
import { ProfileListComponent as AppProfileListComponent } from '@app/ucap/organization/components/profile-list.component';
|
||||||
}
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-sections-organization-member-list',
|
selector: 'app-sections-organization-member-list',
|
||||||
templateUrl: './member-list.component.html',
|
templateUrl: './member-list.component.html',
|
||||||
styleUrls: ['./member-list.component.scss'],
|
styleUrls: ['./member-list.component.scss'],
|
||||||
providers: [
|
|
||||||
{
|
|
||||||
provide: VIRTUAL_SCROLL_STRATEGY,
|
|
||||||
useClass: MemberVirtualScrollStrategy
|
|
||||||
}
|
|
||||||
],
|
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class MemberListComponent implements OnInit, OnDestroy {
|
export class MemberListComponent implements OnInit, OnDestroy {
|
||||||
@Input()
|
@Input()
|
||||||
set searchData(data: {
|
set searchData(searchData: SearchData) {
|
||||||
companyCode: string;
|
this._searchData = searchData;
|
||||||
searchWord: string;
|
|
||||||
isSearch: boolean;
|
if (searchData.bySearch) {
|
||||||
}) {
|
this.setCompanyInfo(searchData.companyCode);
|
||||||
this._searchData = data;
|
} else {
|
||||||
|
this.setDeptInfo(searchData.deptSeq);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ViewChild('profileList', { static: false })
|
||||||
|
profileList: AppProfileListComponent;
|
||||||
|
|
||||||
// tslint:disable-next-line: variable-name
|
// tslint:disable-next-line: variable-name
|
||||||
_searchData: {
|
_searchData: SearchData;
|
||||||
companyCode: string;
|
loginRes: LoginResponse;
|
||||||
searchWord: string;
|
selectedDeptInfo: DeptInfo;
|
||||||
isSearch: boolean;
|
selectedCompanyInfo: Company;
|
||||||
|
searchedProfileLength: number;
|
||||||
|
selectedUserInfos: UserInfoSS[] = [];
|
||||||
|
isExpanded = false;
|
||||||
|
sortOrderForProfileList: SortOrder = {
|
||||||
|
property: 'name',
|
||||||
|
ascending: true
|
||||||
};
|
};
|
||||||
|
|
||||||
private ngOnDestroySubject: Subject<void>;
|
private ngOnDestroySubject: Subject<void>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private store: Store<any>,
|
private store: Store<any>,
|
||||||
private queryProtocolService: QueryProtocolService,
|
|
||||||
private changeDetectorRef: ChangeDetectorRef
|
private changeDetectorRef: ChangeDetectorRef
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.ngOnDestroySubject = new Subject();
|
this.ngOnDestroySubject = new Subject();
|
||||||
|
|
||||||
|
this.store
|
||||||
|
.pipe(takeUntil(this.ngOnDestroySubject), select(LoginSelector.loginRes))
|
||||||
|
.subscribe((loginRes) => {
|
||||||
|
this.loginRes = loginRes;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
|
@ -92,11 +86,131 @@ export class MemberListComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onChangedSearch(data: {
|
onChangedSearch(data: { deptSeq: string; searchWord: string }) {
|
||||||
isSearch: boolean;
|
this._searchData = {
|
||||||
companyCode: string;
|
bySearch: true,
|
||||||
searchWord: string;
|
...data
|
||||||
}) {
|
};
|
||||||
this._searchData = data;
|
this.setDeptInfo(data.deptSeq);
|
||||||
|
}
|
||||||
|
|
||||||
|
onSearchedProfileList(userInfos: UserInfoSS[]) {
|
||||||
|
this.searchedProfileLength = !!userInfos ? userInfos.length : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangedCheckProfileList(
|
||||||
|
datas: { checked: boolean; userInfo: UserInfoSS }[]
|
||||||
|
) {
|
||||||
|
if (!datas || 0 === datas.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pushs: UserInfoSS[] = [];
|
||||||
|
const pops: UserInfoSS[] = [];
|
||||||
|
|
||||||
|
datas.forEach((d) => {
|
||||||
|
const i = this.selectedUserInfos.findIndex(
|
||||||
|
(u) => u.seq === d.userInfo.seq
|
||||||
|
);
|
||||||
|
if (d.checked) {
|
||||||
|
if (-1 === i) {
|
||||||
|
pushs.push(d.userInfo);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (-1 < i) {
|
||||||
|
pops.push(d.userInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (0 < pushs.length) {
|
||||||
|
this.selectedUserInfos = [...this.selectedUserInfos, ...pushs];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 < pops.length) {
|
||||||
|
this.selectedUserInfos = this.selectedUserInfos.filter(
|
||||||
|
(u) => -1 === pops.findIndex((p) => p.seq === u.seq)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onRemovedProfileSelection(userInfo: UserInfo) {
|
||||||
|
const i = this.selectedUserInfos.findIndex(
|
||||||
|
(u) => u.seq === String(userInfo.seq)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (-1 < i) {
|
||||||
|
this.selectedUserInfos = this.selectedUserInfos.filter(
|
||||||
|
(u) => u.seq !== String(userInfo.seq)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removableForSelection = (userInfo: UserInfo) => {
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
colorForSelection = (userInfo: UserInfo) => {
|
||||||
|
return 'accent';
|
||||||
|
};
|
||||||
|
|
||||||
|
onOpenedSelection() {
|
||||||
|
this.isExpanded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
onClosedSelection() {
|
||||||
|
this.isExpanded = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickToggleSort() {
|
||||||
|
this.sortOrderForProfileList = {
|
||||||
|
...this.sortOrderForProfileList,
|
||||||
|
ascending: !this.sortOrderForProfileList.ascending
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeSelectAll(event: MatCheckboxChange) {
|
||||||
|
if (event.checked) {
|
||||||
|
this.profileList.checkAll();
|
||||||
|
} else {
|
||||||
|
this.selectedUserInfos = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private setCompanyInfo(companyCode: string) {
|
||||||
|
const destroySubject: Subject<void> = new Subject();
|
||||||
|
this.store
|
||||||
|
.pipe(takeUntil(destroySubject), select(CompanySelector.companyList))
|
||||||
|
.subscribe((companyList) => {
|
||||||
|
if (!companyList) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.selectedCompanyInfo = companyList.find(
|
||||||
|
(c) => c.companyCode === companyCode
|
||||||
|
);
|
||||||
|
this.changeDetectorRef.markForCheck();
|
||||||
|
destroySubject.next();
|
||||||
|
destroySubject.complete();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private setDeptInfo(seq: string) {
|
||||||
|
const destroySubject: Subject<void> = new Subject();
|
||||||
|
this.store
|
||||||
|
.pipe(
|
||||||
|
takeUntil(destroySubject),
|
||||||
|
select(DepartmentSelector.departmentInfoList)
|
||||||
|
)
|
||||||
|
.subscribe((departmentInfoList) => {
|
||||||
|
if (!departmentInfoList) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.selectedDeptInfo = departmentInfoList.find(
|
||||||
|
(d) => String(d.seq) === seq
|
||||||
|
);
|
||||||
|
this.changeDetectorRef.markForCheck();
|
||||||
|
destroySubject.next();
|
||||||
|
destroySubject.complete();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import { MatChipsModule } from '@angular/material/chips';
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatExpansionModule } from '@angular/material/expansion';
|
import { MatExpansionModule } from '@angular/material/expansion';
|
||||||
|
import { MatSidenavModule } from '@angular/material/sidenav';
|
||||||
|
|
||||||
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
|
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
|
||||||
|
|
||||||
|
@ -42,6 +43,7 @@ import { COMPONENTS } from './components';
|
||||||
MatTableModule,
|
MatTableModule,
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
MatExpansionModule,
|
MatExpansionModule,
|
||||||
|
MatSidenavModule,
|
||||||
|
|
||||||
PerfectScrollbarModule,
|
PerfectScrollbarModule,
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import { Observable } from 'rxjs';
|
import { Observable, of, forkJoin } from 'rxjs';
|
||||||
import { take, concatMap, map } from 'rxjs/operators';
|
import { take, concatMap, map, catchError } from 'rxjs/operators';
|
||||||
|
|
||||||
import { Injectable, Inject, ChangeDetectorRef } from '@angular/core';
|
import { Injectable, Inject, ChangeDetectorRef } from '@angular/core';
|
||||||
|
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
|
|
||||||
import { LocaleCode } from '@ucap/core';
|
import { LocaleCode, DeviceType, FileUtil } from '@ucap/core';
|
||||||
|
|
||||||
import { PasswordUtil } from '@ucap/pi';
|
import { PasswordUtil } from '@ucap/pi';
|
||||||
import { LoginResponse, SSOMode } from '@ucap/protocol-authentication';
|
import { LoginResponse, SSOMode } from '@ucap/protocol-authentication';
|
||||||
|
@ -26,7 +26,12 @@ import { UserStore } from '@app/models/user-store';
|
||||||
import { AppKey } from '@app/types/app-key.type';
|
import { AppKey } from '@app/types/app-key.type';
|
||||||
|
|
||||||
import { environment } from '@environments';
|
import { environment } from '@environments';
|
||||||
import { RoomInfo, RoomType } from '@ucap/protocol-room';
|
import {
|
||||||
|
RoomInfo,
|
||||||
|
RoomType,
|
||||||
|
OpenRequest,
|
||||||
|
Open3Request
|
||||||
|
} from '@ucap/protocol-room';
|
||||||
import { Dictionary } from '@ngrx/entity';
|
import { Dictionary } from '@ngrx/entity';
|
||||||
import {
|
import {
|
||||||
RoomUserMap,
|
RoomUserMap,
|
||||||
|
@ -38,6 +43,31 @@ import {
|
||||||
TranslateService
|
TranslateService
|
||||||
} from '@ucap/ng-ui-organization';
|
} from '@ucap/ng-ui-organization';
|
||||||
import { I18nService } from '@ucap/ng-i18n';
|
import { I18nService } from '@ucap/ng-i18n';
|
||||||
|
import { ChattingActions, RoomActions } from '@ucap/ng-store-chat';
|
||||||
|
import {
|
||||||
|
SendRequest as SendEventRequest,
|
||||||
|
EventType
|
||||||
|
} from '@ucap/protocol-event';
|
||||||
|
import {
|
||||||
|
MassTalkSaveRequest,
|
||||||
|
FileTalkSaveResponse,
|
||||||
|
FileTalkSaveRequest
|
||||||
|
} from '@ucap/api-common';
|
||||||
|
import { CommonApiService } from '@ucap/ng-api-common';
|
||||||
|
import { StatusCode, FileUploadItem } from '@ucap/api';
|
||||||
|
import { LogService } from '@ucap/ng-logger';
|
||||||
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
|
import {
|
||||||
|
AlertDialogComponent,
|
||||||
|
AlertDialogData,
|
||||||
|
AlertDialogResult
|
||||||
|
} from '@ucap/ng-ui';
|
||||||
|
import { StickerFilesInfo, KEY_STICKER_HISTORY } from '@ucap/ng-core';
|
||||||
|
import {
|
||||||
|
CreateDialogComponent,
|
||||||
|
CreateDialogData,
|
||||||
|
CreateDialogResult
|
||||||
|
} from '@app/sections/chat/dialogs/create.dialog.component';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
|
@ -46,8 +76,21 @@ export class AppChatService {
|
||||||
defaultProfileImage = 'assets/images/ico/img_nophoto.svg';
|
defaultProfileImage = 'assets/images/ico/img_nophoto.svg';
|
||||||
defaultProfileImageMulti = 'assets/images/ico/img_nophoto.svg';
|
defaultProfileImageMulti = 'assets/images/ico/img_nophoto.svg';
|
||||||
|
|
||||||
constructor(private i18nService: I18nService) {}
|
constructor(
|
||||||
|
private i18nService: I18nService,
|
||||||
|
private dialog: MatDialog,
|
||||||
|
private localStorageService: LocalStorageService,
|
||||||
|
private store: Store<any>,
|
||||||
|
private commonApiService: CommonApiService,
|
||||||
|
private logService: LogService
|
||||||
|
) {
|
||||||
|
this.i18nService.setDefaultNamespace('chat');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 방이름 생성.
|
||||||
|
* cf) 방이름이 지정되어 있다면 방이름 리턴, 지정되어 있지 않으면 방참여인원의 이름 조합.
|
||||||
|
*/
|
||||||
getRoomName(
|
getRoomName(
|
||||||
organizationTranslate: OrganizationTranslate,
|
organizationTranslate: OrganizationTranslate,
|
||||||
loginRes: LoginResponse,
|
loginRes: LoginResponse,
|
||||||
|
@ -109,6 +152,12 @@ export class AppChatService {
|
||||||
return roomName;
|
return roomName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 방 프로필 이미지 생성.
|
||||||
|
* cf) 방 참여인원의 프로필을 리턴.
|
||||||
|
* 없으면, defaultProfileImage, defaultProfileImageMulti,
|
||||||
|
* 멀티룸은 기본 defaultProfileImageMulti
|
||||||
|
*/
|
||||||
getRoomProfileImage(
|
getRoomProfileImage(
|
||||||
roomInfo: RoomInfo,
|
roomInfo: RoomInfo,
|
||||||
loginRes: LoginResponse,
|
loginRes: LoginResponse,
|
||||||
|
@ -164,6 +213,11 @@ export class AppChatService {
|
||||||
return roomImage;
|
return roomImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 방 인원 정보 수집.
|
||||||
|
* cf) roomUserShort, roomUser 데이터가 쌍을 이루는데 수집방법에 따라 short 만 존재할 수 있어, 수집할 수 있는 방인원을 리턴.
|
||||||
|
* roomUser 가 detail 정보라 우선함.
|
||||||
|
*/
|
||||||
getRoomUserList(
|
getRoomUserList(
|
||||||
loginRes: LoginResponse,
|
loginRes: LoginResponse,
|
||||||
roomId: string,
|
roomId: string,
|
||||||
|
@ -197,4 +251,431 @@ export class AppChatService {
|
||||||
users
|
users
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 스티커 히스토리 관리 in localstorage.
|
||||||
|
* cf) 스티커 전송 성공분만 처리.
|
||||||
|
*/
|
||||||
|
setStickerHistory(sticker: StickerFilesInfo) {
|
||||||
|
const history = this.localStorageService.get<string[]>(KEY_STICKER_HISTORY);
|
||||||
|
|
||||||
|
if (!!history && history.length > 0) {
|
||||||
|
const stickers: string[] = [];
|
||||||
|
[sticker.index, ...history.filter((hist) => hist !== sticker.index)].map(
|
||||||
|
(s, i) => {
|
||||||
|
if (i < 10) {
|
||||||
|
stickers.push(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
this.localStorageService.set<string[]>(KEY_STICKER_HISTORY, stickers);
|
||||||
|
} else {
|
||||||
|
this.localStorageService.set<string[]>(KEY_STICKER_HISTORY, [
|
||||||
|
sticker.index
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event Send Protocol Service.
|
||||||
|
*/
|
||||||
|
protected sendEvent(
|
||||||
|
senderSeq: string,
|
||||||
|
roomId: string,
|
||||||
|
eventType: EventType,
|
||||||
|
sentMessage: string
|
||||||
|
) {
|
||||||
|
this.store.dispatch(
|
||||||
|
ChattingActions.send({
|
||||||
|
senderSeq,
|
||||||
|
req: {
|
||||||
|
roomId,
|
||||||
|
eventType,
|
||||||
|
sentMessage
|
||||||
|
} as SendEventRequest
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Send Normal message */
|
||||||
|
sendMessageOfNormal(senderSeq: string, roomId: string, sentMessage: string) {
|
||||||
|
this.sendEvent(senderSeq, roomId, EventType.Character, sentMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Send Masstext message */
|
||||||
|
sendMessageOfMassText(
|
||||||
|
loginRes: LoginResponse,
|
||||||
|
deviceType: DeviceType,
|
||||||
|
roomId: string,
|
||||||
|
sentMessage: string
|
||||||
|
) {
|
||||||
|
const req: MassTalkSaveRequest = {
|
||||||
|
userSeq: loginRes.userSeq,
|
||||||
|
deviceType,
|
||||||
|
token: loginRes.tokenString,
|
||||||
|
content: sentMessage.replace(/"/g, '\\"'),
|
||||||
|
roomId
|
||||||
|
};
|
||||||
|
|
||||||
|
this.commonApiService
|
||||||
|
.massTalkSave(req)
|
||||||
|
.pipe(
|
||||||
|
take(1),
|
||||||
|
map((res) => {
|
||||||
|
if (res.statusCode === StatusCode.Success) {
|
||||||
|
this.sendEvent(
|
||||||
|
loginRes.userSeq,
|
||||||
|
roomId,
|
||||||
|
EventType.MassText,
|
||||||
|
res.returnJson
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this.logService.error(
|
||||||
|
`commonApiService] massTalkSave ${res?.errorMessage}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
catchError((error) => of({ error }))
|
||||||
|
)
|
||||||
|
.subscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
async sendMessageOfSticker(
|
||||||
|
senderSeq: string,
|
||||||
|
roomId: string,
|
||||||
|
selectedSticker: StickerFilesInfo,
|
||||||
|
sentMessage: string
|
||||||
|
) {
|
||||||
|
// Validation
|
||||||
|
if (
|
||||||
|
!!sentMessage &&
|
||||||
|
sentMessage.trim().length > environment.productConfig.chat.masstextLength
|
||||||
|
) {
|
||||||
|
const result = await this.dialog.open<
|
||||||
|
AlertDialogComponent,
|
||||||
|
AlertDialogData,
|
||||||
|
AlertDialogResult
|
||||||
|
>(AlertDialogComponent, {
|
||||||
|
panelClass: 'miniSize-dialog',
|
||||||
|
data: {
|
||||||
|
title: this.i18nService.t('errors.label'),
|
||||||
|
message: this.i18nService.t('errors.maxLengthOfMassText', {
|
||||||
|
maxLength: environment.productConfig.chat.masstextLength
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send
|
||||||
|
this.sendEvent(
|
||||||
|
senderSeq,
|
||||||
|
roomId,
|
||||||
|
EventType.Sticker,
|
||||||
|
JSON.stringify({
|
||||||
|
name: '스티커',
|
||||||
|
file: selectedSticker.index,
|
||||||
|
chat: !!sentMessage ? sentMessage.trim() : ''
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// set sticker's history in localstorage
|
||||||
|
this.setStickerHistory(selectedSticker);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Send Translation message */
|
||||||
|
sendMessageOfTranslate(
|
||||||
|
loginRes: LoginResponse,
|
||||||
|
deviceType: DeviceType,
|
||||||
|
destLocale: string,
|
||||||
|
roomId: string,
|
||||||
|
sentMessage: string,
|
||||||
|
selectedSticker?: StickerFilesInfo
|
||||||
|
) {
|
||||||
|
// const destLocale = this.destLocale;
|
||||||
|
// const original = message;
|
||||||
|
// const roomSeq = this.roomInfoSubject.value.roomSeq;
|
||||||
|
// if (!!this.isTranslationProcess) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// this.isTranslationProcess = true;
|
||||||
|
// this.commonApiService
|
||||||
|
// .translationSave({
|
||||||
|
// userSeq: this.loginResSubject.value.userSeq,
|
||||||
|
// deviceType: this.environmentsInfo.deviceType,
|
||||||
|
// token: this.loginResSubject.value.tokenString,
|
||||||
|
// roomSeq,
|
||||||
|
// original,
|
||||||
|
// srcLocale: '',
|
||||||
|
// destLocale
|
||||||
|
// } as TranslationSaveRequest)
|
||||||
|
// .pipe(
|
||||||
|
// take(1),
|
||||||
|
// map((res) => {
|
||||||
|
// if (res.statusCode === StatusCode.Success) {
|
||||||
|
// let sentMessage = '';
|
||||||
|
// let eventType = EventType.Translation;
|
||||||
|
// let previewObject: TranslationEventJson | MassTranslationEventJson;
|
||||||
|
// if (res.translationSeq > 0) {
|
||||||
|
// // Mass Text Translation
|
||||||
|
// previewObject = res;
|
||||||
|
// sentMessage = res.returnJson;
|
||||||
|
// eventType = EventType.MassTranslation;
|
||||||
|
// } else {
|
||||||
|
// // Normal Text Translation
|
||||||
|
// previewObject = {
|
||||||
|
// locale: destLocale,
|
||||||
|
// original,
|
||||||
|
// translation: res.translation,
|
||||||
|
// stickername: '',
|
||||||
|
// stickerfile: !!this.selectedSticker
|
||||||
|
// ? this.selectedSticker.index
|
||||||
|
// : ''
|
||||||
|
// };
|
||||||
|
// sentMessage = JSON.stringify(previewObject);
|
||||||
|
// eventType = EventType.Translation;
|
||||||
|
// }
|
||||||
|
// if (!!this.translationPreview) {
|
||||||
|
// // preview
|
||||||
|
// this.translationPreviewInfo = {
|
||||||
|
// previewInfo: res,
|
||||||
|
// translationType: eventType
|
||||||
|
// };
|
||||||
|
// this.changeDetectorRef.detectChanges();
|
||||||
|
// } else {
|
||||||
|
// // direct send
|
||||||
|
// this.store.dispatch(
|
||||||
|
// EventStore.send({
|
||||||
|
// senderSeq: this.loginResSubject.value.userSeq,
|
||||||
|
// req: {
|
||||||
|
// roomSeq,
|
||||||
|
// eventType,
|
||||||
|
// sentMessage
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// );
|
||||||
|
// if (!!this.translationPreviewInfo) {
|
||||||
|
// this.translationPreviewInfo = null;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if (!!this.selectedSticker) {
|
||||||
|
// this.isShowStickerSelector = false;
|
||||||
|
// this.setStickerHistory(this.selectedSticker);
|
||||||
|
// this.selectedSticker = null;
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// this.isTranslationProcess = false;
|
||||||
|
// this.dialogService.open<
|
||||||
|
// AlertDialogComponent,
|
||||||
|
// AlertDialogData,
|
||||||
|
// AlertDialogResult
|
||||||
|
// >(AlertDialogComponent, {
|
||||||
|
// panelClass: 'miniSize-dialog',
|
||||||
|
// data: {
|
||||||
|
// title: '',
|
||||||
|
// message: this.translateService.instant(
|
||||||
|
// 'chat.error.translateServerError'
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// this.logger.error('res', res);
|
||||||
|
// }
|
||||||
|
// }),
|
||||||
|
// catchError((error) => {
|
||||||
|
// this.isTranslationProcess = false;
|
||||||
|
// this.dialogService.open<
|
||||||
|
// AlertDialogComponent,
|
||||||
|
// AlertDialogData,
|
||||||
|
// AlertDialogResult
|
||||||
|
// >(AlertDialogComponent, {
|
||||||
|
// panelClass: 'miniSize-dialog',
|
||||||
|
// data: {
|
||||||
|
// title: '',
|
||||||
|
// message: this.translateService.instant(
|
||||||
|
// 'chat.error.translateServerError'
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// return of(this.logger.error('error', error));
|
||||||
|
// })
|
||||||
|
// )
|
||||||
|
// .subscribe(() => {
|
||||||
|
// this.isTranslationProcess = false;
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Send AttachFile message */
|
||||||
|
sendMessageOfAttachFile(
|
||||||
|
loginRes: LoginResponse,
|
||||||
|
deviceType: DeviceType,
|
||||||
|
roomId: string,
|
||||||
|
fileUploadItems: FileUploadItem[]
|
||||||
|
): Promise<boolean> {
|
||||||
|
const executor = async (
|
||||||
|
resolve: (value?: boolean | PromiseLike<boolean>) => void,
|
||||||
|
reject: (reason?: any) => void
|
||||||
|
) => {
|
||||||
|
const allObservables: Observable<FileTalkSaveResponse>[] = [];
|
||||||
|
|
||||||
|
for (const fileUploadItem of fileUploadItems) {
|
||||||
|
let thumbnail: File;
|
||||||
|
if (
|
||||||
|
-1 !==
|
||||||
|
[
|
||||||
|
'3gp',
|
||||||
|
'avi',
|
||||||
|
'm4v',
|
||||||
|
'mkv',
|
||||||
|
'mov',
|
||||||
|
'mp4',
|
||||||
|
'mpeg',
|
||||||
|
'mpg',
|
||||||
|
'rv',
|
||||||
|
'ts',
|
||||||
|
'webm',
|
||||||
|
'wmv'
|
||||||
|
].indexOf(FileUtil.getExtension(fileUploadItem.file.name))
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
thumbnail = await FileUtil.thumbnail(fileUploadItem.file);
|
||||||
|
} catch (err) {
|
||||||
|
this.logService.error('video thumbnail error.', err);
|
||||||
|
}
|
||||||
|
this.logService.debug('thumbnail', thumbnail);
|
||||||
|
}
|
||||||
|
|
||||||
|
const req: FileTalkSaveRequest = {
|
||||||
|
userSeq: loginRes.userSeq,
|
||||||
|
deviceType,
|
||||||
|
token: loginRes.tokenString,
|
||||||
|
roomId,
|
||||||
|
file: fileUploadItem.file,
|
||||||
|
fileName: fileUploadItem.file.name,
|
||||||
|
thumb: thumbnail,
|
||||||
|
fileUploadItem
|
||||||
|
};
|
||||||
|
|
||||||
|
allObservables.push(
|
||||||
|
this.commonApiService.fileTalkSave(req).pipe(
|
||||||
|
map((res) => {
|
||||||
|
if (!res) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (StatusCode.Success === res.statusCode) {
|
||||||
|
return res;
|
||||||
|
} else {
|
||||||
|
throw res;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
forkJoin(allObservables)
|
||||||
|
.pipe(take(1))
|
||||||
|
.subscribe(
|
||||||
|
(resList) => {
|
||||||
|
for (const res of resList) {
|
||||||
|
this.store.dispatch(
|
||||||
|
ChattingActions.send({
|
||||||
|
senderSeq: loginRes.userSeq,
|
||||||
|
req: {
|
||||||
|
roomId,
|
||||||
|
eventType: EventType.File,
|
||||||
|
sentMessage: JSON.stringify(res.returnJson)
|
||||||
|
} as SendEventRequest
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
this.logService.debug('onFileSelected error', error);
|
||||||
|
const msg = this.i18nService.t('common.file.errors.failToUpload');
|
||||||
|
alert(msg);
|
||||||
|
|
||||||
|
reject(msg);
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
resolve(true);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return new Promise<boolean>(executor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open Dialog for 'New Room Open'.
|
||||||
|
*/
|
||||||
|
newOpenRoomDialog(): void {
|
||||||
|
const dialogRef = this.dialog.open<
|
||||||
|
CreateDialogComponent,
|
||||||
|
CreateDialogData,
|
||||||
|
CreateDialogResult
|
||||||
|
>(CreateDialogComponent, {
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
data: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
dialogRef
|
||||||
|
.afterClosed()
|
||||||
|
.pipe(
|
||||||
|
take(1),
|
||||||
|
map((result) => {
|
||||||
|
if (!!result && !!result.userSeqs && result.userSeqs.length > 0) {
|
||||||
|
this.newOpenRoom(result.userSeqs, result.isTimer);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
catchError((err) => {
|
||||||
|
return of(err);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.subscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
newOpenRoom(
|
||||||
|
userSeqs: string[],
|
||||||
|
isTimerRoom: boolean,
|
||||||
|
loginRes?: LoginResponse
|
||||||
|
) {
|
||||||
|
if (!userSeqs || userSeqs.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
isTimerRoom = isTimerRoom || false;
|
||||||
|
|
||||||
|
if (!!isTimerRoom) {
|
||||||
|
/** Timer Room Open. */
|
||||||
|
const req: Open3Request = {
|
||||||
|
divCd: 'OPROOMT',
|
||||||
|
roomName: '',
|
||||||
|
isTimerRoom,
|
||||||
|
timerRoomInterval:
|
||||||
|
environment.productConfig.chat.timerRoomDefaultInterval,
|
||||||
|
userSeqs
|
||||||
|
};
|
||||||
|
this.store.dispatch(RoomActions.createTimer({ req }));
|
||||||
|
} else {
|
||||||
|
/** Normal Room Open */
|
||||||
|
let req: OpenRequest;
|
||||||
|
if (
|
||||||
|
userSeqs.length === 1 &&
|
||||||
|
!!loginRes &&
|
||||||
|
userSeqs[0] === loginRes.userSeq
|
||||||
|
) {
|
||||||
|
// MyTalk Open.
|
||||||
|
req = {
|
||||||
|
divCd: 'OPMYTALK',
|
||||||
|
userSeqs: [loginRes.talkWithMeBotSeq + '']
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
req = {
|
||||||
|
divCd: 'OPROOM',
|
||||||
|
userSeqs
|
||||||
|
};
|
||||||
|
}
|
||||||
|
this.store.dispatch(RoomActions.create({ req }));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
86
src/app/services/app-file.service.ts
Normal file
86
src/app/services/app-file.service.ts
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
import { Injectable, Inject } from '@angular/core';
|
||||||
|
|
||||||
|
import { FileUtil } from '@ucap/core';
|
||||||
|
import { I18nService, UCAP_I18N_NAMESPACE } from '@ucap/ng-i18n';
|
||||||
|
import { CommonApiService } from '@ucap/ng-api-common';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class AppFileService {
|
||||||
|
constructor(
|
||||||
|
private store: Store<any>,
|
||||||
|
private i18nService: I18nService,
|
||||||
|
private commonApiService: CommonApiService
|
||||||
|
) {
|
||||||
|
this.i18nService.setDefaultNamespace('common');
|
||||||
|
}
|
||||||
|
|
||||||
|
async validUploadFile(
|
||||||
|
fileList: FileList,
|
||||||
|
fileAllowSize: number = 50
|
||||||
|
): Promise<boolean> {
|
||||||
|
let valid = true;
|
||||||
|
|
||||||
|
// File size check.
|
||||||
|
// tslint:disable-next-line: prefer-for-of
|
||||||
|
for (let i = 0; i < fileList.length; i++) {
|
||||||
|
const file = fileList[i];
|
||||||
|
if (file.size > fileAllowSize * 1024 * 1024) {
|
||||||
|
const msg = this.i18nService.t('common.file.errors.oversize', {
|
||||||
|
maxSize: fileAllowSize
|
||||||
|
});
|
||||||
|
alert(msg);
|
||||||
|
|
||||||
|
valid = false;
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extention check.
|
||||||
|
const checkExt = this.commonApiService.acceptableExtensionForFileTalk(
|
||||||
|
FileUtil.getExtensions(fileList)
|
||||||
|
);
|
||||||
|
if (!!checkExt) {
|
||||||
|
const msg = this.i18nService.t('common.file.errors.notSupporedType', {
|
||||||
|
supporedType: checkExt.join(',')
|
||||||
|
});
|
||||||
|
alert(msg);
|
||||||
|
// this.snackBarService.openFromComponent<
|
||||||
|
// AlertSnackbarComponent,
|
||||||
|
// AlertSnackbarData
|
||||||
|
// >(AlertSnackbarComponent, {
|
||||||
|
// duration: 1000,
|
||||||
|
// verticalPosition: 'bottom',
|
||||||
|
// horizontalPosition: 'center',
|
||||||
|
// data: {
|
||||||
|
// html: this.translateService.instant(
|
||||||
|
// 'common.file.errors.notSupporedType',
|
||||||
|
// {
|
||||||
|
// supporedType: checkExt.join(',')
|
||||||
|
// }
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
valid = false;
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fake media file check.
|
||||||
|
const fakeMedia = await this.commonApiService.checkInvalidMediaMimeForFileTalkForFileList(
|
||||||
|
fileList
|
||||||
|
);
|
||||||
|
if (!!fakeMedia) {
|
||||||
|
const msg = this.i18nService.t('common.file.errors.notAcceptableMime', {
|
||||||
|
supporedType: fakeMedia.join(',')
|
||||||
|
});
|
||||||
|
alert(msg);
|
||||||
|
|
||||||
|
valid = false;
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
}
|
6
src/app/types/group-user.dialog.type.ts
Normal file
6
src/app/types/group-user.dialog.type.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
export enum GroupUserDialaogType {
|
||||||
|
Create = 'CREATE_GROUP',
|
||||||
|
Add = 'ADD_GROUP',
|
||||||
|
Copy = 'COPY_GROUP',
|
||||||
|
Move = 'MOVE_GROUP'
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
export * from './app-key.type';
|
export * from './app-key.type';
|
||||||
export * from './select-user.dialog.type';
|
export * from './select-user.dialog.type';
|
||||||
export * from './tokens';
|
export * from './tokens';
|
||||||
|
export * from './group-user.dialog.type';
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<div class="login-container">
|
<div class="login-container ucap-mat-input-container">
|
||||||
<ucap-authentication-login
|
<ucap-authentication-login
|
||||||
[companyList]="companyList"
|
[companyList]="companyList"
|
||||||
[fixedCompanyCode]="fixedCompanyCode"
|
[fixedCompanyCode]="fixedCompanyCode"
|
||||||
|
@ -9,7 +9,7 @@
|
||||||
[loginTry]="loginTry"
|
[loginTry]="loginTry"
|
||||||
(login)="onLogin($event)"
|
(login)="onLogin($event)"
|
||||||
>
|
>
|
||||||
<div ucapAuthenticationLogin="header">
|
<div ucapAuthenticationLogin="header" class="header">
|
||||||
<div class="logo-img">
|
<div class="logo-img">
|
||||||
<img src="../../../assets/images/logo_140.png" alt="" />
|
<img src="../../../assets/images/logo_140.png" alt="" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -47,7 +47,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="login-pass-info">
|
<div class="login-pass-info">
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li matRipple>
|
||||||
<a href="">{{ 'login.labels.forgotPassword' | ucapI18n }}</a>
|
<a href="">{{ 'login.labels.forgotPassword' | ucapI18n }}</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
|
@ -58,7 +58,7 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="login-button-area">
|
<div class="login-button-area">
|
||||||
<button type="button">
|
<button mat-flat-button>
|
||||||
{{ 'login.labels.notesOnUse' | ucapI18n }}
|
{{ 'login.labels.notesOnUse' | ucapI18n }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,32 +1,55 @@
|
||||||
@import '~@ucap/lg-scss/mixins';
|
@import '~@ucap/lg-scss/mixins';
|
||||||
|
|
||||||
|
.login-container {
|
||||||
|
padding: 0 0 45px;
|
||||||
|
width: 420px;
|
||||||
|
margin: auto;
|
||||||
|
text-align: center;
|
||||||
|
flex-basis: auto;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
.header {
|
||||||
|
.logo-img {
|
||||||
|
display: block;
|
||||||
|
text-align: center;
|
||||||
|
img {
|
||||||
|
margin-bottom: 7px;
|
||||||
|
vertical-align: top;
|
||||||
|
@include screen(mid) {
|
||||||
|
width: 120px;
|
||||||
|
}
|
||||||
|
@include screen(xs) {
|
||||||
|
width: 100px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
h1 {
|
h1 {
|
||||||
@include font-family($font-light);
|
@include font-family($font-light);
|
||||||
font-size: 24px;
|
font-size: 1.714em;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: $txt-color01;
|
color: $txt-color01;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
@include screen(mid) {
|
@include screen(mid) {
|
||||||
font-size: 19px;
|
font-size: 1.357em;
|
||||||
}
|
}
|
||||||
@include screen(xs) {
|
@include screen(xs) {
|
||||||
font-size: 14px;
|
font-size: 1em;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-container {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-chk-area {
|
.login-chk-area {
|
||||||
margin-top: 6px;
|
margin-top: 7px;
|
||||||
font-size: 13px;
|
font-size: 0.929em;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
@include screen(xs) {
|
@include screen(xs) {
|
||||||
font-size: 12px;
|
font-size: 0.857em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.login-pass-info {
|
.login-pass-info {
|
||||||
|
@ -62,14 +85,14 @@ h1 {
|
||||||
}
|
}
|
||||||
a {
|
a {
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
font-size: 12px;
|
font-size: 0.857em;
|
||||||
color: $gray-re4a;
|
color: $gray-re4a;
|
||||||
padding-left: 34px;
|
padding-left: 34px;
|
||||||
position: relative;
|
position: relative;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
&::before {
|
&::before {
|
||||||
font-family: 'material Icons';
|
font-family: 'material Icons';
|
||||||
font-size: 18px;
|
font-size: 1.286em;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
content: 'search';
|
content: 'search';
|
||||||
color: $white;
|
color: $white;
|
||||||
|
@ -104,7 +127,7 @@ h1 {
|
||||||
height: 46px;
|
height: 46px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
background-color: #e0e3e7;
|
background-color: #e0e3e7;
|
||||||
font-size: 12px;
|
font-size: 0.857em;
|
||||||
color: $gray-re4a;
|
color: $gray-re4a;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@include screen(mid) {
|
@include screen(mid) {
|
||||||
|
|
|
@ -7,8 +7,24 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div appLayoutsSelector="body">
|
<div appLayoutsSelector="body">
|
||||||
<div class="file-item" *ngFor="let item of fileList">
|
<div class="file-item" *ngFor="let fileUploadItem of fileUploadItems">
|
||||||
<span class="file-name">{{ item.name }}</span>
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="1.5"
|
||||||
|
stroke-linecap="butt"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<div class="file-upload-name">{{ fileUploadItem.file.name }}</div>
|
||||||
<button
|
<button
|
||||||
mat-icon-button
|
mat-icon-button
|
||||||
matSuffix
|
matSuffix
|
||||||
|
@ -18,8 +34,13 @@
|
||||||
>
|
>
|
||||||
<mat-icon>close</mat-icon>
|
<mat-icon>close</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<div class="progress-area" style="width: 100%;" *ngIf="item.progress">
|
|
||||||
<mat-progress-bar mode="determinate" value="75"> </mat-progress-bar>
|
<div class="progress-area" style="width: 100%;">
|
||||||
|
<mat-progress-bar
|
||||||
|
mode="determinate"
|
||||||
|
[value]="fileUploadItem.uploadingProgress$ | async"
|
||||||
|
>
|
||||||
|
</mat-progress-bar>
|
||||||
<button
|
<button
|
||||||
mat-icon-button
|
mat-icon-button
|
||||||
matSuffix
|
matSuffix
|
||||||
|
@ -34,11 +55,11 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div appLayoutsSelector="footer">
|
<div appLayoutsSelector="footer">
|
||||||
<button mat-button aria-label="모두에게 보내기">
|
<button mat-button aria-label="취소">
|
||||||
모두에게 보내기
|
취소
|
||||||
</button>
|
</button>
|
||||||
<button mat-button aria-label="나에게 보내기">
|
<button mat-button aria-label="완료">
|
||||||
나에게 보내기
|
완료
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</app-layout-selector>
|
</app-layout-selector>
|
||||||
|
|
|
@ -1,35 +1,103 @@
|
||||||
import {
|
import {
|
||||||
Component,
|
Component,
|
||||||
OnInit,
|
OnInit,
|
||||||
Input,
|
|
||||||
ElementRef,
|
ElementRef,
|
||||||
AfterViewInit,
|
AfterViewInit,
|
||||||
Inject
|
ChangeDetectorRef,
|
||||||
|
ChangeDetectionStrategy
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
|
import { FileUploadItem } from '@ucap/api';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-chat-selector-file-upload',
|
selector: 'app-chat-selector-file-upload',
|
||||||
templateUrl: './file-upload.selector.component.html',
|
templateUrl: './file-upload.selector.component.html',
|
||||||
styleUrls: ['./file-upload.selector.component.scss']
|
styleUrls: ['./file-upload.selector.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class FileUploadSelectorComponent implements OnInit, AfterViewInit {
|
export class FileUploadSelectorComponent implements OnInit, AfterViewInit {
|
||||||
fileList: { name: string; progress: boolean }[];
|
fileUploadItems: FileUploadItem[];
|
||||||
|
uploadItems: DataTransferItem[];
|
||||||
|
|
||||||
constructor() {}
|
constructor(
|
||||||
|
private elementRef: ElementRef<HTMLElement>,
|
||||||
|
private changeDetectorRef: ChangeDetectorRef
|
||||||
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {}
|
||||||
this.fileList = [
|
|
||||||
{ name: 'UCAP 메신저 UX 가이드_V0.1_0309.pptx', progress: false },
|
|
||||||
{ name: 'UCAP 메신저 UX .1_0309.pptx', progress: false },
|
|
||||||
{ name: 'UCAP 메신저 가이드_V0.1_0309.pptx', progress: true },
|
|
||||||
{ name: 'UCAP 메신저 UX 가이드_V.1_0309.pptx', progress: true },
|
|
||||||
{ name: 'UCAP 메신저 UX 가이드_V0.1_0309.pptx', progress: false },
|
|
||||||
{ name: 'UCAP 메신저 UX 가이드_V0..pptx', progress: false },
|
|
||||||
{ name: 'UCAP 메신저 UX 가이드_V0.1_0309.pptx', progress: false },
|
|
||||||
{ name: ' 메신저 UX 가이드_V0.1_0309.pptx', progress: false },
|
|
||||||
{ name: 'UCAP 메신저 UX 가이드_V0.1_0309.pptx', progress: false }
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
ngAfterViewInit(): void {}
|
ngAfterViewInit(): void {}
|
||||||
|
|
||||||
|
onDragEnter(items: DataTransferItemList): void {
|
||||||
|
if (!items || 0 === items.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uploadItems: DataTransferItem[] = [];
|
||||||
|
// tslint:disable-next-line: prefer-for-of
|
||||||
|
for (let i = 0; i < items.length; i++) {
|
||||||
|
uploadItems.push(items[i]);
|
||||||
|
}
|
||||||
|
this.uploadItems = [...uploadItems];
|
||||||
|
this.changeStyleDisplay(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
onDragLeave(): void {
|
||||||
|
this.changeStyleDisplay(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
onDrop(fileUploadItems: FileUploadItem[]) {
|
||||||
|
if (!fileUploadItems || 0 === fileUploadItems.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.fileUploadItems = fileUploadItems;
|
||||||
|
this.uploadItems = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
onFileSelected(fileUploadItems: FileUploadItem[]): void {
|
||||||
|
if (!fileUploadItems || 0 === fileUploadItems.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.fileUploadItems = fileUploadItems;
|
||||||
|
this.uploadItems = undefined;
|
||||||
|
this.changeStyleDisplay(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
onUploadComplete(): void {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.fileUploadItems = undefined;
|
||||||
|
this.changeStyleDisplay(false);
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
isEventInElement(event: DragEvent): boolean {
|
||||||
|
const rect = this.elementRef.nativeElement.getBoundingClientRect();
|
||||||
|
// const rect: DOMRect = this.elementRef.nativeElement.getBoundingClientRect();
|
||||||
|
|
||||||
|
if (
|
||||||
|
event.pageX >= rect.left &&
|
||||||
|
event.pageX <= rect.left + rect.width &&
|
||||||
|
event.pageY >= rect.top &&
|
||||||
|
event.pageY <= rect.top + rect.height
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private changeStyleDisplay(show: boolean): void {
|
||||||
|
// if (show || (!!this.fileUploadItems && 0 < this.fileUploadItems.length)) {
|
||||||
|
// if (this.dropZoneIncludeParent) {
|
||||||
|
// this.elementRef.nativeElement.parentElement.style.display = '';
|
||||||
|
// } else {
|
||||||
|
// this.elementRef.nativeElement.style.display = '';
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// if (this.dropZoneIncludeParent) {
|
||||||
|
// this.elementRef.nativeElement.parentElement.style.display = 'none';
|
||||||
|
// } else {
|
||||||
|
// this.elementRef.nativeElement.style.display = 'none';
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
this.changeDetectorRef.detectChanges();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
highlight: highlight
|
highlight: highlight
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
isMe : {{ isMe }}
|
|
||||||
<ucap-chat-message-box-read-here
|
<ucap-chat-message-box-read-here
|
||||||
id="message-box-readhere"
|
id="message-box-readhere"
|
||||||
*ngIf="existReadToHere"
|
*ngIf="existReadToHere"
|
||||||
|
@ -19,14 +18,13 @@
|
||||||
</ucap-chat-message-box-date-splitter>
|
</ucap-chat-message-box-date-splitter>
|
||||||
|
|
||||||
<div #mbChatRow class="chat-row">
|
<div #mbChatRow class="chat-row">
|
||||||
<div *ngIf="isInformation; then information; else contents"></div>
|
<div *ngIf="isInformation(message); then information; else contents"></div>
|
||||||
<ng-template #information>
|
<ng-template #information>
|
||||||
<ng-container class="bubble" [ngSwitch]="message.type">
|
<ng-container class="bubble" [ngSwitch]="message.type">
|
||||||
Information...
|
|
||||||
<ucap-chat-message-box-information
|
<ucap-chat-message-box-information
|
||||||
*ngSwitchCase="EventType.Join"
|
*ngSwitchCase="EventType.Join"
|
||||||
|
[message]="message"
|
||||||
></ucap-chat-message-box-information>
|
></ucap-chat-message-box-information>
|
||||||
-->
|
|
||||||
|
|
||||||
<ucap-chat-message-box-information
|
<ucap-chat-message-box-information
|
||||||
*ngSwitchCase="EventType.Exit"
|
*ngSwitchCase="EventType.Exit"
|
||||||
|
@ -65,7 +63,7 @@
|
||||||
<img
|
<img
|
||||||
ucapImage
|
ucapImage
|
||||||
[base]="profileImageRoot"
|
[base]="profileImageRoot"
|
||||||
[path]="senderInfo.profileImageFile"
|
[path]="senderInfo?.profileImageFile"
|
||||||
[default]="defaultProfileImage"
|
[default]="defaultProfileImage"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -91,33 +89,40 @@
|
||||||
<div class="contents">
|
<div class="contents">
|
||||||
<ng-container
|
<ng-container
|
||||||
class="bubble"
|
class="bubble"
|
||||||
*ngIf="
|
*ngIf="!isInformation(message)"
|
||||||
messageType !== EventType.NotificationForTimerRoom &&
|
|
||||||
!isInformation
|
|
||||||
"
|
|
||||||
[ngSwitch]="message.type"
|
[ngSwitch]="message.type"
|
||||||
>
|
>
|
||||||
<ucap-chat-message-box-text
|
<ucap-chat-message-box-text
|
||||||
*ngSwitchCase="EventType.Character"
|
*ngSwitchCase="EventType.Character"
|
||||||
[message]="message"
|
[message]="message"
|
||||||
|
(openLink)="onOpenLink($event)"
|
||||||
>
|
>
|
||||||
</ucap-chat-message-box-text>
|
</ucap-chat-message-box-text>
|
||||||
|
|
||||||
<ucap-chat-message-box-file
|
<ucap-chat-message-box-file
|
||||||
*ngSwitchCase="EventType.File"
|
*ngSwitchCase="EventType.File"
|
||||||
[message]="message"
|
[message]="message"
|
||||||
|
[roomInfo]="roomInfo"
|
||||||
>
|
>
|
||||||
</ucap-chat-message-box-file>
|
</ucap-chat-message-box-file>
|
||||||
|
|
||||||
<ucap-chat-message-box-sticker
|
<ucap-chat-message-box-sticker
|
||||||
*ngSwitchCase="EventType.Sticker"
|
*ngSwitchCase="EventType.Sticker"
|
||||||
[message]="message"
|
[message]="message"
|
||||||
|
(openLink)="onOpenLink($event)"
|
||||||
>
|
>
|
||||||
|
<img
|
||||||
|
ucapUiChatStickerComponent="stickerImage"
|
||||||
|
[src]="getStickerImage(message)"
|
||||||
|
onerror="this.src='assets/sticker/sticker_default.png'"
|
||||||
|
/>
|
||||||
</ucap-chat-message-box-sticker>
|
</ucap-chat-message-box-sticker>
|
||||||
|
|
||||||
<ucap-chat-message-box-mass
|
<ucap-chat-message-box-mass
|
||||||
*ngSwitchCase="EventType.MassText"
|
*ngSwitchCase="EventType.MassText"
|
||||||
[message]="message"
|
[message]="message"
|
||||||
|
(openLink)="onOpenLink($event)"
|
||||||
|
(massDetail)="onOpenMassDetail($event)"
|
||||||
>
|
>
|
||||||
</ucap-chat-message-box-mass>
|
</ucap-chat-message-box-mass>
|
||||||
|
|
||||||
|
@ -136,11 +141,13 @@
|
||||||
<ucap-chat-message-box-translation
|
<ucap-chat-message-box-translation
|
||||||
*ngSwitchCase="EventType.Translation"
|
*ngSwitchCase="EventType.Translation"
|
||||||
[message]="message"
|
[message]="message"
|
||||||
|
(openLink)="onOpenLink($event)"
|
||||||
></ucap-chat-message-box-translation>
|
></ucap-chat-message-box-translation>
|
||||||
|
|
||||||
<ucap-chat-message-box-mass-translation
|
<ucap-chat-message-box-mass-translation
|
||||||
*ngSwitchCase="EventType.MassTranslation"
|
*ngSwitchCase="EventType.MassTranslation"
|
||||||
[message]="message"
|
[message]="message"
|
||||||
|
(openLink)="onOpenLink($event)"
|
||||||
>
|
>
|
||||||
</ucap-chat-message-box-mass-translation>
|
</ucap-chat-message-box-mass-translation>
|
||||||
|
|
||||||
|
|
|
@ -7,22 +7,52 @@ import {
|
||||||
AfterViewInit,
|
AfterViewInit,
|
||||||
ElementRef,
|
ElementRef,
|
||||||
ViewChild,
|
ViewChild,
|
||||||
ChangeDetectorRef
|
ChangeDetectorRef,
|
||||||
|
OnDestroy
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { Info, EventJson, EventType, FileType } from '@ucap/protocol-event';
|
|
||||||
|
import { Store, select } from '@ngrx/store';
|
||||||
|
import { map, catchError, takeUntil, take } from 'rxjs/operators';
|
||||||
|
import { of, Subject } from 'rxjs';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Info,
|
||||||
|
EventJson,
|
||||||
|
EventType,
|
||||||
|
FileType,
|
||||||
|
StickerEventJson
|
||||||
|
} from '@ucap/protocol-event';
|
||||||
import {
|
import {
|
||||||
UserInfo as RoomUserInfo,
|
UserInfo as RoomUserInfo,
|
||||||
UserInfoShort as RoomUserInfoShort
|
UserInfoShort as RoomUserInfoShort,
|
||||||
|
RoomInfo
|
||||||
} from '@ucap/protocol-room';
|
} from '@ucap/protocol-room';
|
||||||
|
import { LoginResponse } from '@ucap/protocol-authentication';
|
||||||
|
import { LoginSession } from '@ucap/core';
|
||||||
|
|
||||||
|
import { I18nService } from '@ucap/ng-i18n';
|
||||||
|
import { LocalStorageService } from '@ucap/ng-web-storage';
|
||||||
|
import { LogService } from '@ucap/ng-logger';
|
||||||
|
import { CommonApiService } from '@ucap/ng-api-common';
|
||||||
|
|
||||||
|
import { AppAuthenticationService } from '@app/services/app-authentication.service';
|
||||||
|
|
||||||
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
|
import { LoginSelector } from '@ucap/ng-store-authentication';
|
||||||
|
import { MassTalkDownloadRequest } from '@ucap/api-common';
|
||||||
|
import { StatusCode } from '@ucap/api';
|
||||||
|
import { Dictionary } from '@ngrx/entity';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-chat-message-box',
|
selector: 'app-chat-message-box',
|
||||||
templateUrl: './message-box.component.html',
|
templateUrl: './message-box.component.html',
|
||||||
styleUrls: ['./message-box.component.scss']
|
styleUrls: ['./message-box.component.scss']
|
||||||
})
|
})
|
||||||
export class MessageBoxComponent implements OnInit, AfterViewInit {
|
export class MessageBoxComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
@Input()
|
@Input()
|
||||||
message: Info<EventJson>;
|
message: Info<EventJson>;
|
||||||
|
@Input()
|
||||||
|
roomInfo: RoomInfo;
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
isMe = false;
|
isMe = false;
|
||||||
|
@ -38,23 +68,129 @@ export class MessageBoxComponent implements OnInit, AfterViewInit {
|
||||||
@Input()
|
@Input()
|
||||||
unreadCount: number;
|
unreadCount: number;
|
||||||
|
|
||||||
|
loginSession: LoginSession;
|
||||||
|
loginRes: LoginResponse;
|
||||||
|
|
||||||
EventType = EventType;
|
EventType = EventType;
|
||||||
|
|
||||||
//////////////////////////////////
|
//////////////////////////////////
|
||||||
@Input()
|
@Input()
|
||||||
messageType: string;
|
messageType: string;
|
||||||
@Input()
|
@Input()
|
||||||
isInformation = false;
|
|
||||||
@Input()
|
|
||||||
highlight = false;
|
highlight = false;
|
||||||
@Input()
|
@Input()
|
||||||
existReadToHere = false;
|
existReadToHere = false;
|
||||||
@Input()
|
@Input()
|
||||||
fileType: FileType;
|
fileType: FileType;
|
||||||
|
|
||||||
constructor() {}
|
private ngOnDestroySubject: Subject<boolean>;
|
||||||
|
constructor(
|
||||||
|
private store: Store<any>,
|
||||||
|
private i18nService: I18nService,
|
||||||
|
private dialog: MatDialog,
|
||||||
|
private localStorageService: LocalStorageService,
|
||||||
|
private logService: LogService,
|
||||||
|
private appAuthenticationService: AppAuthenticationService,
|
||||||
|
private commonApiService: CommonApiService,
|
||||||
|
private changeDetectorRef: ChangeDetectorRef
|
||||||
|
) {}
|
||||||
|
|
||||||
ngOnInit() {}
|
ngOnInit() {
|
||||||
|
this.ngOnDestroySubject = new Subject<boolean>();
|
||||||
|
this.store
|
||||||
|
.pipe(takeUntil(this.ngOnDestroySubject), select(LoginSelector.loginRes))
|
||||||
|
.subscribe((loginRes) => {
|
||||||
|
this.loginRes = loginRes;
|
||||||
|
});
|
||||||
|
this.appAuthenticationService
|
||||||
|
.getLoginSession$()
|
||||||
|
.pipe(takeUntil(this.ngOnDestroySubject))
|
||||||
|
.subscribe((loginSession) => (this.loginSession = loginSession));
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
if (!!this.ngOnDestroySubject) {
|
||||||
|
this.ngOnDestroySubject.complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ngAfterViewInit(): void {}
|
ngAfterViewInit(): void {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 정보성 Event 인지 판단.
|
||||||
|
* @description 정보성 event 일 경우 프로필, 일시 를 표현하지 않는다.
|
||||||
|
* Edit with reducers.ts / sync / updateRoomForNewEventMessage
|
||||||
|
*/
|
||||||
|
isInformation(info: Info<EventJson>) {
|
||||||
|
if (
|
||||||
|
info.type === EventType.Join ||
|
||||||
|
info.type === EventType.Exit ||
|
||||||
|
info.type === EventType.ForcedExit ||
|
||||||
|
info.type === EventType.RenameRoom ||
|
||||||
|
info.type === EventType.NotificationForiOSCapture ||
|
||||||
|
info.type === EventType.NotificationForTimerRoom ||
|
||||||
|
info.type === EventType.GuideForRoomTimerChanged
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Sticker image.
|
||||||
|
*/
|
||||||
|
getStickerImage(message: Info<EventJson>): string {
|
||||||
|
if (!!message.sentMessageJson) {
|
||||||
|
return `assets/sticker/sticker_s_${
|
||||||
|
(message.sentMessageJson as StickerEventJson).file
|
||||||
|
}.png`;
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Url link Open Event.
|
||||||
|
*/
|
||||||
|
onOpenLink(url: string): void {
|
||||||
|
console.log('onOpenLink', url);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detail view > Mass text.
|
||||||
|
*/
|
||||||
|
onOpenMassDetail(eventMassSeq: number): void {
|
||||||
|
const req = {
|
||||||
|
userSeq: this.loginRes.userSeq,
|
||||||
|
deviceType: this.loginSession.deviceType,
|
||||||
|
eventMassSeq: Number(eventMassSeq),
|
||||||
|
token: this.loginRes.tokenString
|
||||||
|
} as MassTalkDownloadRequest;
|
||||||
|
|
||||||
|
this.commonApiService
|
||||||
|
.massTalkDownload(req)
|
||||||
|
.pipe(
|
||||||
|
take(1),
|
||||||
|
map((res) => {
|
||||||
|
if (res.statusCode === StatusCode.Success) {
|
||||||
|
console.log('massTalkDownload', res.content);
|
||||||
|
// const result = this.dialog.open<
|
||||||
|
// MassDetailComponent,
|
||||||
|
// MassDetailDialogData
|
||||||
|
// >(MassDetailComponent, {
|
||||||
|
// data: {
|
||||||
|
// title: this.i18nService.t('chat.detailView'),
|
||||||
|
// contents: res.content
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
} else {
|
||||||
|
this.logService.error(
|
||||||
|
`commonApiService] massTalkDownload ${res?.errorMessage}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
catchError((error) => of({ error }))
|
||||||
|
)
|
||||||
|
.subscribe();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,10 @@
|
||||||
|
|
||||||
<ng-template ucapChatRoomExpansionHeader let-node>
|
<ng-template ucapChatRoomExpansionHeader let-node>
|
||||||
<span class="header-buddy">
|
<span class="header-buddy">
|
||||||
<span>{{ node.nodeType }} {{ node.nodeType | ucapDate: 'dddd' }}</span>
|
<span
|
||||||
|
>{{ node.nodeType | ucapDate: 'LL' }}
|
||||||
|
{{ node.nodeType | ucapDate: 'dddd' }}</span
|
||||||
|
>
|
||||||
<span *ngIf="isToday(node.nodeType)">
|
<span *ngIf="isToday(node.nodeType)">
|
||||||
({{ 'room.today' | ucapI18n }})
|
({{ 'room.today' | ucapI18n }})
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -151,10 +151,18 @@ export class RoomExpansionComponent implements OnInit, OnDestroy {
|
||||||
this.loginRes = loginRes;
|
this.loginRes = loginRes;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.store
|
combineLatest([
|
||||||
.pipe(takeUntil(this.ngOnDestroySubject), select(RoomSelector.rooms))
|
this.store.pipe(select(RoomSelector.rooms)),
|
||||||
.subscribe((rooms) => {
|
this.store.pipe(select(RoomSelector.standbyRooms))
|
||||||
rooms = (rooms || []).filter((info) => info.isJoinRoom);
|
])
|
||||||
|
.pipe(takeUntil(this.ngOnDestroySubject))
|
||||||
|
.subscribe(([rooms, standbyRooms]) => {
|
||||||
|
rooms = (rooms || []).filter((info) => {
|
||||||
|
return (
|
||||||
|
info.isJoinRoom &&
|
||||||
|
!standbyRooms.find((standbyRoom) => standbyRoom === info.roomId)
|
||||||
|
);
|
||||||
|
});
|
||||||
this.roomList = rooms;
|
this.roomList = rooms;
|
||||||
|
|
||||||
// groupping.
|
// groupping.
|
||||||
|
@ -201,7 +209,7 @@ export class RoomExpansionComponent implements OnInit, OnDestroy {
|
||||||
const date = roomInfo.finalEventDate;
|
const date = roomInfo.finalEventDate;
|
||||||
let division = '';
|
let division = '';
|
||||||
try {
|
try {
|
||||||
const value = this.dateService.get(date, 'LL');
|
const value = this.dateService.get(date, 'YYYYMMDD');
|
||||||
|
|
||||||
if (value === 'Invalid date') {
|
if (value === 'Invalid date') {
|
||||||
division = date;
|
division = date;
|
||||||
|
@ -295,8 +303,8 @@ export class RoomExpansionComponent implements OnInit, OnDestroy {
|
||||||
ConfirmDialogResult
|
ConfirmDialogResult
|
||||||
>(ConfirmDialogComponent, {
|
>(ConfirmDialogComponent, {
|
||||||
data: {
|
data: {
|
||||||
title: this.i18nService.t('room.dialog.titleExitFromRoom'),
|
title: this.i18nService.t('dialog.title.exitFromRoom'),
|
||||||
html: this.i18nService.t('room.dialog.confirmExitFromRoom')
|
html: this.i18nService.t('dialog.confirmExitFromRoom')
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,19 @@ import {
|
||||||
Input,
|
Input,
|
||||||
ElementRef,
|
ElementRef,
|
||||||
AfterViewInit,
|
AfterViewInit,
|
||||||
Inject
|
Inject,
|
||||||
|
Output,
|
||||||
|
EventEmitter
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
|
import {
|
||||||
|
StickerInfo,
|
||||||
|
StickerFilesInfo,
|
||||||
|
StickerUtil,
|
||||||
|
StickerMap,
|
||||||
|
ActiveAndOrdering,
|
||||||
|
KEY_STICKER_HISTORY
|
||||||
|
} from '@ucap/ng-core';
|
||||||
|
import { LocalStorageService } from '@ucap/ng-web-storage';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-chat-selector-sticker',
|
selector: 'app-chat-selector-sticker',
|
||||||
|
@ -13,6 +24,12 @@ import {
|
||||||
styleUrls: ['./sticker.selector.component.scss']
|
styleUrls: ['./sticker.selector.component.scss']
|
||||||
})
|
})
|
||||||
export class StickerSelectorComponent implements OnInit, AfterViewInit {
|
export class StickerSelectorComponent implements OnInit, AfterViewInit {
|
||||||
|
@Output()
|
||||||
|
selectedSticker = new EventEmitter<StickerFilesInfo>();
|
||||||
|
|
||||||
|
@Output()
|
||||||
|
closeSticker = new EventEmitter();
|
||||||
|
|
||||||
stickerHistory: string[] = [];
|
stickerHistory: string[] = [];
|
||||||
|
|
||||||
stickerBasePath = '../../../../assets/sticker/';
|
stickerBasePath = '../../../../assets/sticker/';
|
||||||
|
@ -22,10 +39,20 @@ export class StickerSelectorComponent implements OnInit, AfterViewInit {
|
||||||
|
|
||||||
currentTabIndex: number;
|
currentTabIndex: number;
|
||||||
|
|
||||||
constructor() {}
|
customStickerMap: StickerInfo[] = [...StickerMap];
|
||||||
|
activeAndOrdering: string[] = [...ActiveAndOrdering];
|
||||||
|
|
||||||
|
constructor(private localStorageService: LocalStorageService) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.stickerInfoList = StickerUtil.getStickerInfoList();
|
this.stickerHistory = this.localStorageService.get<string[]>(
|
||||||
|
KEY_STICKER_HISTORY
|
||||||
|
);
|
||||||
|
|
||||||
|
this.stickerInfoList = StickerUtil.getStickerInfoList(
|
||||||
|
this.customStickerMap,
|
||||||
|
this.activeAndOrdering
|
||||||
|
);
|
||||||
this.currentTabIndex = 0;
|
this.currentTabIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +86,7 @@ export class StickerSelectorComponent implements OnInit, AfterViewInit {
|
||||||
this.stickerHistory.forEach((sticker) => {
|
this.stickerHistory.forEach((sticker) => {
|
||||||
const arr: string[] = sticker.split('_');
|
const arr: string[] = sticker.split('_');
|
||||||
if (arr.length === 2) {
|
if (arr.length === 2) {
|
||||||
const sInfo: StickerInfo[] = StickerMap.filter(
|
const sInfo: StickerInfo[] = this.customStickerMap.filter(
|
||||||
(s) => s.index === arr[0]
|
(s) => s.index === arr[0]
|
||||||
);
|
);
|
||||||
if (!!sInfo && sInfo.length > 0) {
|
if (!!sInfo && sInfo.length > 0) {
|
||||||
|
@ -84,180 +111,10 @@ export class StickerSelectorComponent implements OnInit, AfterViewInit {
|
||||||
|
|
||||||
onClickSelectSticker(sticker: StickerFilesInfo) {
|
onClickSelectSticker(sticker: StickerFilesInfo) {
|
||||||
this.currentSticker = sticker;
|
this.currentSticker = sticker;
|
||||||
|
this.selectedSticker.emit(sticker);
|
||||||
}
|
}
|
||||||
|
|
||||||
onClickClose() {}
|
onClickClose() {
|
||||||
}
|
this.closeSticker.emit();
|
||||||
|
|
||||||
export interface StickerInfo {
|
|
||||||
index: string;
|
|
||||||
title: string;
|
|
||||||
iconPath: string;
|
|
||||||
iconPathOn: string;
|
|
||||||
useYn: boolean;
|
|
||||||
fileInfos: StickerFilesInfo[];
|
|
||||||
}
|
|
||||||
export interface StickerFilesInfo {
|
|
||||||
index: string;
|
|
||||||
path: string;
|
|
||||||
}
|
|
||||||
export const StickerMap: StickerInfo[] = [
|
|
||||||
{
|
|
||||||
index: '00',
|
|
||||||
title: 'History',
|
|
||||||
iconPath: 'sticker_cate00.png',
|
|
||||||
iconPathOn: 'sticker_cate00_f.png',
|
|
||||||
useYn: true,
|
|
||||||
fileInfos: []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
index: '01',
|
|
||||||
title: '꼼므',
|
|
||||||
iconPath: 'sticker_cate01.png',
|
|
||||||
iconPathOn: 'sticker_cate01_f.png',
|
|
||||||
useYn: true,
|
|
||||||
fileInfos: [
|
|
||||||
{ index: '01_01', path: 'sticker_s_01_01.png' },
|
|
||||||
{ index: '01_02', path: 'sticker_s_01_02.png' },
|
|
||||||
{ index: '01_03', path: 'sticker_s_01_03.png' },
|
|
||||||
{ index: '01_04', path: 'sticker_s_01_04.png' },
|
|
||||||
{ index: '01_05', path: 'sticker_s_01_05.png' },
|
|
||||||
{ index: '01_06', path: 'sticker_s_01_06.png' },
|
|
||||||
{ index: '01_07', path: 'sticker_s_01_07.png' },
|
|
||||||
{ index: '01_08', path: 'sticker_s_01_08.png' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
index: '02',
|
|
||||||
title: '까미',
|
|
||||||
iconPath: 'sticker_cate02.png',
|
|
||||||
iconPathOn: 'sticker_cate02_f.png',
|
|
||||||
useYn: true,
|
|
||||||
fileInfos: [
|
|
||||||
{ index: '02_02', path: 'sticker_s_02_02.png' },
|
|
||||||
{ index: '02_03', path: 'sticker_s_02_03.png' },
|
|
||||||
{ index: '02_04', path: 'sticker_s_02_04.png' },
|
|
||||||
{ index: '02_05', path: 'sticker_s_02_05.png' },
|
|
||||||
{ index: '02_06', path: 'sticker_s_02_06.png' },
|
|
||||||
{ index: '02_07', path: 'sticker_s_02_07.png' },
|
|
||||||
{ index: '02_08', path: 'sticker_s_02_08.png' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
index: '03',
|
|
||||||
title: '왈도',
|
|
||||||
iconPath: 'sticker_cate03.png',
|
|
||||||
iconPathOn: 'sticker_cate03_f.png',
|
|
||||||
useYn: true,
|
|
||||||
fileInfos: [
|
|
||||||
{ index: '03_01', path: 'sticker_s_03_01.png' },
|
|
||||||
{ index: '03_02', path: 'sticker_s_03_02.png' },
|
|
||||||
{ index: '03_03', path: 'sticker_s_03_03.png' },
|
|
||||||
{ index: '03_04', path: 'sticker_s_03_04.png' },
|
|
||||||
{ index: '03_05', path: 'sticker_s_03_05.png' },
|
|
||||||
{ index: '03_06', path: 'sticker_s_03_06.png' },
|
|
||||||
{ index: '03_07', path: 'sticker_s_03_07.png' },
|
|
||||||
{ index: '03_08', path: 'sticker_s_03_08.png' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
index: '04',
|
|
||||||
title: '웅쓰',
|
|
||||||
iconPath: 'sticker_cate04.png',
|
|
||||||
iconPathOn: 'sticker_cate04_f.png',
|
|
||||||
useYn: true,
|
|
||||||
fileInfos: [
|
|
||||||
{ index: '04_01', path: 'sticker_s_04_01.png' },
|
|
||||||
{ index: '04_02', path: 'sticker_s_04_02.png' },
|
|
||||||
{ index: '04_03', path: 'sticker_s_04_03.png' },
|
|
||||||
{ index: '04_04', path: 'sticker_s_04_04.png' },
|
|
||||||
{ index: '04_05', path: 'sticker_s_04_05.png' },
|
|
||||||
{ index: '04_06', path: 'sticker_s_04_06.png' },
|
|
||||||
{ index: '04_07', path: 'sticker_s_04_07.png' },
|
|
||||||
{ index: '04_08', path: 'sticker_s_04_08.png' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
index: '05',
|
|
||||||
title: '말풍선',
|
|
||||||
iconPath: 'sticker_cate05.png',
|
|
||||||
iconPathOn: 'sticker_cate05_f.png',
|
|
||||||
useYn: true,
|
|
||||||
fileInfos: [
|
|
||||||
{ index: '05_01', path: 'sticker_s_05_01.png' },
|
|
||||||
{ index: '05_02', path: 'sticker_s_05_02.png' },
|
|
||||||
{ index: '05_03', path: 'sticker_s_05_03.png' },
|
|
||||||
{ index: '05_04', path: 'sticker_s_05_04.png' },
|
|
||||||
{ index: '05_05', path: 'sticker_s_05_05.png' },
|
|
||||||
{ index: '05_06', path: 'sticker_s_05_06.png' },
|
|
||||||
{ index: '05_07', path: 'sticker_s_05_07.png' },
|
|
||||||
{ index: '05_08', path: 'sticker_s_05_08.png' },
|
|
||||||
{ index: '05_09', path: 'sticker_s_05_09.png' },
|
|
||||||
{ index: '05_10', path: 'sticker_s_05_10.png' },
|
|
||||||
{ index: '05_11', path: 'sticker_s_05_11.png' },
|
|
||||||
{ index: '05_12', path: 'sticker_s_05_12.png' },
|
|
||||||
{ index: '05_13', path: 'sticker_s_05_13.png' },
|
|
||||||
{ index: '05_14', path: 'sticker_s_05_14.png' },
|
|
||||||
{ index: '05_15', path: 'sticker_s_05_15.png' },
|
|
||||||
{ index: '05_16', path: 'sticker_s_05_16.png' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
index: '12',
|
|
||||||
title: '황소',
|
|
||||||
iconPath: 'sticker_cate12.png',
|
|
||||||
iconPathOn: 'sticker_cate12_f.png',
|
|
||||||
useYn: true,
|
|
||||||
fileInfos: [
|
|
||||||
{ index: '12_01', path: 'sticker_s_12_01.gif' },
|
|
||||||
{ index: '12_02', path: 'sticker_s_12_02.gif' },
|
|
||||||
{ index: '12_03', path: 'sticker_s_12_03.gif' },
|
|
||||||
{ index: '12_04', path: 'sticker_s_12_04.gif' },
|
|
||||||
{ index: '12_05', path: 'sticker_s_12_05.gif' },
|
|
||||||
{ index: '12_06', path: 'sticker_s_12_06.gif' },
|
|
||||||
{ index: '12_07', path: 'sticker_s_12_07.gif' },
|
|
||||||
{ index: '12_08', path: 'sticker_s_12_08.gif' },
|
|
||||||
{ index: '12_09', path: 'sticker_s_12_09.gif' },
|
|
||||||
{ index: '12_10', path: 'sticker_s_12_10.gif' },
|
|
||||||
{ index: '12_11', path: 'sticker_s_12_11.gif' },
|
|
||||||
{ index: '12_12', path: 'sticker_s_12_12.gif' },
|
|
||||||
{ index: '12_13', path: 'sticker_s_12_13.gif' },
|
|
||||||
{ index: '12_14', path: 'sticker_s_12_14.gif' },
|
|
||||||
{ index: '12_15', path: 'sticker_s_12_15.gif' },
|
|
||||||
{ index: '12_16', path: 'sticker_s_12_16.gif' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const ActiveAndOrdering: string[] = ['00', '01', '02', '03', '04', '05'];
|
|
||||||
|
|
||||||
export class StickerUtil {
|
|
||||||
static getStickerInfoList(): StickerInfo[] {
|
|
||||||
const rtnStickerList: StickerInfo[] = [];
|
|
||||||
|
|
||||||
ActiveAndOrdering.forEach((idx) => {
|
|
||||||
const stickerInfos: StickerInfo[] = StickerMap.filter(
|
|
||||||
(sticker) => sticker.index === idx && sticker.useYn
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!!stickerInfos && stickerInfos.length > 0) {
|
|
||||||
rtnStickerList.push(stickerInfos[0]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return rtnStickerList;
|
|
||||||
}
|
|
||||||
|
|
||||||
static getStickerInfoSub(index: string): StickerFilesInfo[] {
|
|
||||||
const stickerFilesList: StickerFilesInfo[] = [];
|
|
||||||
const stickerInfos: StickerInfo[] = StickerMap.filter(
|
|
||||||
(sticker) => sticker.index === index && sticker.useYn
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!!stickerInfos && stickerInfos.length > 0) {
|
|
||||||
stickerFilesList.concat(stickerInfos[0].fileInfos);
|
|
||||||
}
|
|
||||||
|
|
||||||
return stickerFilesList;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,22 +8,18 @@
|
||||||
[selectedUserList]="selectedUserList"
|
[selectedUserList]="selectedUserList"
|
||||||
[checkable]="checkable"
|
[checkable]="checkable"
|
||||||
(clickMoreMenu)="!isDialog ? onClickMoreMenu($event) : null"
|
(clickMoreMenu)="!isDialog ? onClickMoreMenu($event) : null"
|
||||||
(checkGroup)="onCheckGroup($event)"
|
(checkGroup)="onToggleCheckGroup($event)"
|
||||||
>
|
>
|
||||||
<ng-template ucapGroupExpansionNode let-node>
|
<ng-template ucapGroupExpansionNode let-node>
|
||||||
<app-group-profile-list-item
|
<app-group-profile-list-item-02
|
||||||
[userInfo]="node.userInfo"
|
[userInfo]="node.userInfo"
|
||||||
[isMe]="loginRes?.userSeq === node.userInfo.seq"
|
|
||||||
[group]="node.groupDetail"
|
|
||||||
defaultProfileImage="assets/images/img_nophoto_50.png"
|
|
||||||
[profileImageRoot]="versionInfo2Res?.profileRoot"
|
|
||||||
[checkable]="checkable"
|
[checkable]="checkable"
|
||||||
[presence]="getStatusBulkInfo(node.userInfo) | async"
|
[isDialog]="isDialog"
|
||||||
[isChecked]="getCheckedUser(node.userInfo)"
|
[checked]="getCheckedUser(node.userInfo)"
|
||||||
(checked)="onCheckedUser($event)"
|
[isMe]="loginRes?.userSeq === node.userInfo.seq"
|
||||||
(click)="onClickUser($event, node.userInfo)"
|
|
||||||
(moreMenu)="onClikeMoreProfile($event)"
|
(moreMenu)="onClikeMoreProfile($event)"
|
||||||
></app-group-profile-list-item>
|
(changeCheckUser)="onChangeCheckUser($event)"
|
||||||
|
></app-group-profile-list-item-02>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
<ng-template ucapGroupExpansionFavoriteHeader let-node>
|
<ng-template ucapGroupExpansionFavoriteHeader let-node>
|
||||||
|
@ -109,7 +105,7 @@
|
||||||
#profileContextMenuTrigger="matMenuTrigger"
|
#profileContextMenuTrigger="matMenuTrigger"
|
||||||
[matMenuTriggerFor]="profileContextMenu"
|
[matMenuTriggerFor]="profileContextMenu"
|
||||||
></div>
|
></div>
|
||||||
<mat-menu #profileContextMenu="matMenu">
|
<mat-menu #profileContextMenu="matMenu" (closed)="onProfileMenuClose($event)">
|
||||||
<ng-template
|
<ng-template
|
||||||
matMenuContent
|
matMenuContent
|
||||||
let-userInfo="userInfo"
|
let-userInfo="userInfo"
|
||||||
|
@ -177,46 +173,5 @@
|
||||||
>
|
>
|
||||||
{{ 'moreMenu.profile.removeBuddy' | ucapI18n }}
|
{{ 'moreMenu.profile.removeBuddy' | ucapI18n }}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<!-- <button
|
|
||||||
mat-menu-item
|
|
||||||
*ngIf="getShowProfileContextMenu('REGISTER_NICKNAME', userInfo, group)"
|
|
||||||
(click)="onClickProfileContextMenu('REGISTER_NICKNAME', userInfo)"
|
|
||||||
>
|
|
||||||
닉네임 설정
|
|
||||||
</button> -->
|
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</mat-menu>
|
</mat-menu>
|
||||||
|
|
||||||
<!-- <div
|
|
||||||
style="visibility: hidden; position: fixed;"
|
|
||||||
[style.left]="editGroupNamePosition.x"
|
|
||||||
[style.top]="editGroupNamePosition.y"
|
|
||||||
#editGroupNameTrigger="matMenuTrigger"
|
|
||||||
[matMenuTriggerFor]="groupNameMenu"
|
|
||||||
></div>
|
|
||||||
|
|
||||||
<mat-menu #groupNameMenu="matMenu">
|
|
||||||
<ng-template matMenuContent let-group="group">
|
|
||||||
<ucap-inline-edit-input
|
|
||||||
[initialMode]="true"
|
|
||||||
(apply)="
|
|
||||||
$event.stopPropagation();
|
|
||||||
onApplyEditGroupName(editGroupInput.value, group)
|
|
||||||
"
|
|
||||||
(edit)="$event.stopPropagation()"
|
|
||||||
(cancel)="$event.stopPropagation(); editGroupInput.value = group.name"
|
|
||||||
class="form-eidt"
|
|
||||||
>
|
|
||||||
<span ucapInlineEditInput="view">{{ group.name }}</span>
|
|
||||||
<span ucapInlineEditInput="edit"
|
|
||||||
><input
|
|
||||||
matInput
|
|
||||||
#editGroupInput
|
|
||||||
type="text"
|
|
||||||
[value]="group.name"
|
|
||||||
(click)="$event.stopPropagation()"
|
|
||||||
/></span>
|
|
||||||
</ucap-inline-edit-input>
|
|
||||||
</ng-template>
|
|
||||||
</mat-menu> -->
|
|
||||||
|
|
|
@ -52,16 +52,9 @@ import { environment } from '@environments';
|
||||||
import { PresenceSelector } from '@ucap/ng-store-organization';
|
import { PresenceSelector } from '@ucap/ng-store-organization';
|
||||||
import { StatusCode } from '@ucap/core';
|
import { StatusCode } from '@ucap/core';
|
||||||
|
|
||||||
import { EditInlineInputDialogComponent } from '@app/sections/group/dialogs/edit-inline-input.dialog.component';
|
|
||||||
import {
|
|
||||||
AlertDialogComponent,
|
|
||||||
AlertDialogData,
|
|
||||||
AlertDialogResult,
|
|
||||||
ConfirmDialogComponent,
|
|
||||||
ConfirmDialogData,
|
|
||||||
ConfirmDialogResult
|
|
||||||
} from '@ucap/ng-ui';
|
|
||||||
import { I18nService } from '@ucap/ng-i18n';
|
import { I18nService } from '@ucap/ng-i18n';
|
||||||
|
import { ProfileListItem01Component } from '@ucap/ng-ui-organization';
|
||||||
|
import { ProfileListItem02Component } from './profile-list-item-02.component';
|
||||||
|
|
||||||
export type UserInfoTypes =
|
export type UserInfoTypes =
|
||||||
| UserInfo
|
| UserInfo
|
||||||
|
@ -104,12 +97,6 @@ export class ExpansionComponent implements OnInit, OnDestroy {
|
||||||
@Input()
|
@Input()
|
||||||
showType: string;
|
showType: string;
|
||||||
|
|
||||||
@Output()
|
|
||||||
checked = new EventEmitter<{
|
|
||||||
isChecked: boolean;
|
|
||||||
userInfo: UserInfoTypes;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
@Output()
|
@Output()
|
||||||
profileMenu: EventEmitter<any> = new EventEmitter();
|
profileMenu: EventEmitter<any> = new EventEmitter();
|
||||||
|
|
||||||
|
@ -119,17 +106,26 @@ export class ExpansionComponent implements OnInit, OnDestroy {
|
||||||
@Output()
|
@Output()
|
||||||
selectGroupMenu = new EventEmitter<{
|
selectGroupMenu = new EventEmitter<{
|
||||||
menuType: string;
|
menuType: string;
|
||||||
group: GroupDetailData;
|
groupBuddyList: { group: GroupDetailData; buddyList: UserInfo[] };
|
||||||
|
rect: any;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
// @Output()
|
@Output()
|
||||||
// editGroupName = new EventEmitter<{
|
selectProfileMenu: EventEmitter<{
|
||||||
// editName: string;
|
menuType: string;
|
||||||
// group: GroupDetailData;
|
userInfo: UserInfoF;
|
||||||
// }>();
|
group: GroupDetailData;
|
||||||
|
rect: any;
|
||||||
|
}> = new EventEmitter();
|
||||||
|
|
||||||
@Output()
|
@Output()
|
||||||
checkGroup = new EventEmitter<{
|
toggleCheckUser: EventEmitter<{
|
||||||
|
checked: boolean;
|
||||||
|
userInfo: UserInfoSS;
|
||||||
|
}> = new EventEmitter();
|
||||||
|
|
||||||
|
@Output()
|
||||||
|
toggleCheckGroup = new EventEmitter<{
|
||||||
isChecked: boolean;
|
isChecked: boolean;
|
||||||
groupBuddyList: { group: GroupDetailData; buddyList: UserInfo[] };
|
groupBuddyList: { group: GroupDetailData; buddyList: UserInfo[] };
|
||||||
}>();
|
}>();
|
||||||
|
@ -178,7 +174,6 @@ export class ExpansionComponent implements OnInit, OnDestroy {
|
||||||
private store: Store<any>,
|
private store: Store<any>,
|
||||||
private changeDetectorRef: ChangeDetectorRef,
|
private changeDetectorRef: ChangeDetectorRef,
|
||||||
private logService: LogService,
|
private logService: LogService,
|
||||||
private dialog: MatDialog,
|
|
||||||
private i18nService: I18nService,
|
private i18nService: I18nService,
|
||||||
@Self() private elementRef: ElementRef
|
@Self() private elementRef: ElementRef
|
||||||
) {}
|
) {}
|
||||||
|
@ -366,10 +361,6 @@ export class ExpansionComponent implements OnInit, OnDestroy {
|
||||||
this.profileMenu.emit({ event, userInfo, group, isSearchData });
|
this.profileMenu.emit({ event, userInfo, group, isSearchData });
|
||||||
}
|
}
|
||||||
|
|
||||||
onCheckedUser(params: { isChecked: boolean; userInfo: UserInfoTypes }) {
|
|
||||||
this.checked.emit(params);
|
|
||||||
}
|
|
||||||
|
|
||||||
onClickUser(event: MouseEvent, userInfo: UserInfo) {
|
onClickUser(event: MouseEvent, userInfo: UserInfo) {
|
||||||
this.clicked.emit({ event, userInfo });
|
this.clicked.emit({ event, userInfo });
|
||||||
}
|
}
|
||||||
|
@ -463,94 +454,59 @@ export class ExpansionComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
onSelectGroupMenu(menuType: string, group: GroupDetailData) {
|
onSelectGroupMenu(menuType: string, group: GroupDetailData) {
|
||||||
|
let rect: any;
|
||||||
|
|
||||||
if (menuType.localeCompare('RENAME') === 0) {
|
if (menuType.localeCompare('RENAME') === 0) {
|
||||||
// this.editablGroup = group;
|
|
||||||
// this.onShowEditGroup(group);
|
|
||||||
const target = this.elementRef.nativeElement.querySelector(
|
const target = this.elementRef.nativeElement.querySelector(
|
||||||
'.mat-tree-node'
|
'.mat-tree-node'
|
||||||
);
|
);
|
||||||
const rect = target.getBoundingClientRect();
|
|
||||||
|
|
||||||
const clickEventY = this.groupMenuEvent.clientY;
|
const clickEventY = this.groupMenuEvent.clientY;
|
||||||
const tartgetY = Math.floor((clickEventY - 150) * 0.1) * 10;
|
const clientRect = target.getBoundingClientRect();
|
||||||
|
|
||||||
const dialogRef = this.dialog.open(EditInlineInputDialogComponent, {
|
rect = {
|
||||||
width: rect.width,
|
width: clientRect.width,
|
||||||
height: rect.height,
|
height: clientRect.height,
|
||||||
panelClass: 'ucap-edit-group-name-dialog',
|
top: clickEventY - 100 + clientRect.height,
|
||||||
data: {
|
left: clientRect.left,
|
||||||
curValue: group.name,
|
bottom: clientRect.bottom,
|
||||||
placeholder: '그룹명을 입력하세요.',
|
right: clientRect.right
|
||||||
left: rect.left,
|
};
|
||||||
top: clickEventY - 100 + rect.height
|
|
||||||
}
|
}
|
||||||
});
|
const groupBuddyList = this.groupBuddies.filter(
|
||||||
|
(g) => g.group.seq === group.seq
|
||||||
dialogRef
|
|
||||||
.afterClosed()
|
|
||||||
.pipe(
|
|
||||||
take(1),
|
|
||||||
map((result) => {
|
|
||||||
if (
|
|
||||||
!!result &&
|
|
||||||
result.choice &&
|
|
||||||
result.curValue.localeCompare(group.name) !== 0
|
|
||||||
) {
|
|
||||||
this.store.dispatch(
|
|
||||||
GroupActions.update({
|
|
||||||
req: {
|
|
||||||
groupSeq: group.seq,
|
|
||||||
groupName: result.curValue,
|
|
||||||
userSeqs: group.userSeqs
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
);
|
||||||
}
|
this.selectGroupMenu.emit({
|
||||||
}),
|
menuType,
|
||||||
catchError((err) => {
|
groupBuddyList: groupBuddyList[0],
|
||||||
return of(err);
|
rect
|
||||||
})
|
|
||||||
)
|
|
||||||
.subscribe();
|
|
||||||
}
|
|
||||||
this.selectGroupMenu.emit({ menuType, group });
|
|
||||||
}
|
|
||||||
|
|
||||||
// onApplyEditGroupName(editName: string, group: GroupDetailData) {
|
|
||||||
// // this.editablGroup = null;
|
|
||||||
// this.editGroupName.emit({
|
|
||||||
// editName,
|
|
||||||
// group
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
onCheckGroup(params: {
|
|
||||||
isChecked: boolean;
|
|
||||||
groupBuddyList: { group: GroupDetailData; buddyList: UserInfo[] };
|
|
||||||
}) {
|
|
||||||
this.checkGroup.emit({
|
|
||||||
isChecked: params.isChecked,
|
|
||||||
groupBuddyList: params.groupBuddyList
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 개별선택(토글) 이벤트 */
|
||||||
|
onChangeCheckUser(param: { checked: boolean; userInfo: UserInfoSS }) {
|
||||||
|
this.toggleCheckUser.emit(param);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 개별 체크여부 */
|
||||||
getCheckedUser(userInfo: UserInfoTypes) {
|
getCheckedUser(userInfo: UserInfoTypes) {
|
||||||
if (!!this.selectedUserList && this.selectedUserList.length > 0) {
|
if (!!this.selectedUserList && this.selectedUserList.length > 0) {
|
||||||
return (
|
return (
|
||||||
this.selectedUserList.filter((item) => item.seq === userInfo.seq)
|
this.selectedUserList.filter(
|
||||||
.length > 0
|
(item) => (item.seq as any) === userInfo.seq
|
||||||
|
).length > 0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
getStatusBulkInfo(buddy: UserInfoTypes) {
|
onToggleCheckGroup(params: {
|
||||||
return this.store.pipe(
|
isChecked: boolean;
|
||||||
select(PresenceSelector.selectEntitiesStatusBulkInfo),
|
groupBuddyList: { group: GroupDetailData; buddyList: UserInfo[] };
|
||||||
map((statusBulkInfo) =>
|
}) {
|
||||||
!!statusBulkInfo ? statusBulkInfo[buddy.seq] : undefined
|
this.toggleCheckGroup.emit({
|
||||||
)
|
isChecked: params.isChecked,
|
||||||
);
|
groupBuddyList: params.groupBuddyList
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getBuddiesForShowType(): { group: GroupDetailData; buddyList: UserInfo[] }[] {
|
getBuddiesForShowType(): { group: GroupDetailData; buddyList: UserInfo[] }[] {
|
||||||
|
@ -592,114 +548,30 @@ export class ExpansionComponent implements OnInit, OnDestroy {
|
||||||
) {
|
) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
switch (menuType) {
|
|
||||||
case 'VIEW_PROFILE':
|
|
||||||
this.onClickUser(event, userInfo as UserInfo);
|
|
||||||
break;
|
|
||||||
case 'REGISTER_FAVORITE':
|
|
||||||
this.store.dispatch(
|
|
||||||
BuddyActions.update({
|
|
||||||
req: {
|
|
||||||
seq: Number(userInfo.seq),
|
|
||||||
isFavorit: !userInfo.isFavorit
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case 'NICKNAME':
|
|
||||||
{
|
|
||||||
this.editNickname(event, userInfo, rect);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'COPY_BUDDY':
|
|
||||||
break;
|
|
||||||
case 'MOVE_BUDDY':
|
|
||||||
break;
|
|
||||||
case 'REMOVE_BUDDY':
|
|
||||||
{
|
|
||||||
this.removeBuddy(userInfo, group);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private removeBuddy(userInfo: UserInfoF, group: GroupDetailData) {
|
const clientRect = {
|
||||||
const dialogRef = this.dialog.open<
|
width: rect.width,
|
||||||
ConfirmDialogComponent,
|
|
||||||
ConfirmDialogData,
|
|
||||||
ConfirmDialogResult
|
|
||||||
>(ConfirmDialogComponent, {
|
|
||||||
data: {
|
|
||||||
title: '',
|
|
||||||
html: this.i18nService.t('label.confirmRemoveBuddy')
|
|
||||||
}
|
|
||||||
});
|
|
||||||
dialogRef
|
|
||||||
.afterClosed()
|
|
||||||
.pipe(
|
|
||||||
take(1),
|
|
||||||
map((result) => {
|
|
||||||
if (!!result && result.choice) {
|
|
||||||
const trgtUserSeq = group.userSeqs.filter(
|
|
||||||
(user) => user + '' !== userInfo.seq + ''
|
|
||||||
);
|
|
||||||
|
|
||||||
this.store.dispatch(
|
|
||||||
GroupActions.updateMember({
|
|
||||||
targetGroup: group,
|
|
||||||
targetUserSeqs: trgtUserSeq
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
catchError((err) => {
|
|
||||||
return of(err);
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.subscribe();
|
|
||||||
}
|
|
||||||
private editNickname(event: MouseEvent, userInfo: UserInfoF, rect: any) {
|
|
||||||
const clickEventY = event.clientY;
|
|
||||||
|
|
||||||
const dialogRef = this.dialog.open(EditInlineInputDialogComponent, {
|
|
||||||
width: rect.width - 30 + '',
|
|
||||||
height: rect.height,
|
height: rect.height,
|
||||||
panelClass: 'ucap-edit-group-name-dialog',
|
top: rect.top,
|
||||||
data: {
|
left: rect.left,
|
||||||
curValue: userInfo.nickName,
|
right: rect.right,
|
||||||
placeholder: '닉네임을 설정하세요.',
|
bottom: rect.bottom
|
||||||
left: rect.left + 70,
|
};
|
||||||
top: rect.top
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
dialogRef
|
if (menuType === 'VIEW_PROFILE') {
|
||||||
.afterClosed()
|
this.onClickUser(event, userInfo as UserInfo);
|
||||||
.pipe(
|
|
||||||
take(1),
|
|
||||||
map((result) => {
|
|
||||||
if (
|
|
||||||
!!result &&
|
|
||||||
result.choice &&
|
|
||||||
result.curValue.localeCompare(userInfo.nickName) !== 0
|
|
||||||
) {
|
|
||||||
this.store.dispatch(
|
|
||||||
BuddyActions.nickname({
|
|
||||||
req: {
|
|
||||||
userSeq: Number(userInfo.seq),
|
|
||||||
nickname: result.curValue
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
);
|
this.selectProfileMenu.emit({
|
||||||
}
|
menuType,
|
||||||
}),
|
userInfo,
|
||||||
catchError((err) => {
|
group,
|
||||||
return of(err);
|
rect: clientRect
|
||||||
})
|
});
|
||||||
)
|
|
||||||
.subscribe();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onProfileMenuClose(event: MouseEvent) {}
|
||||||
|
|
||||||
getShowProfileContextMenu(menuType: string, group: GroupDetailData) {
|
getShowProfileContextMenu(menuType: string, group: GroupDetailData) {
|
||||||
return true;
|
return true;
|
||||||
if (!!this.isSearchData) {
|
if (!!this.isSearchData) {
|
||||||
|
|
|
@ -1,4 +1,10 @@
|
||||||
import { ExpansionComponent } from './expansion.component';
|
import { ExpansionComponent } from './expansion.component';
|
||||||
import { ProfileListItemComponent } from './profile-list-item.component';
|
|
||||||
|
|
||||||
export const COMPONENTS = [ExpansionComponent, ProfileListItemComponent];
|
import { ProfileListItem02Component } from './profile-list-item-02.component';
|
||||||
|
import { ProfileListComponent } from './profile-list.component';
|
||||||
|
|
||||||
|
export const COMPONENTS = [
|
||||||
|
ExpansionComponent,
|
||||||
|
ProfileListItem02Component,
|
||||||
|
ProfileListComponent
|
||||||
|
];
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
<div
|
||||||
|
class="profile-list-container"
|
||||||
|
(mouseover)="onMouseover($event)"
|
||||||
|
(mouseleave)="onMouseleave($event)"
|
||||||
|
>
|
||||||
|
<ucap-organization-profile-list-item-02
|
||||||
|
[userInfo]="userInfo"
|
||||||
|
[checkable]="checkable"
|
||||||
|
[checked]="checked"
|
||||||
|
(openProfile)="onOpenProfile($event)"
|
||||||
|
(changeCheck)="onChangeCheckUser($event)"
|
||||||
|
>
|
||||||
|
<ucap-organization-profile-image-01
|
||||||
|
ucapOrganizationProfileListItem01="profileImage"
|
||||||
|
[userInfo]="userInfo"
|
||||||
|
[profileImageRoot]="versionInfo2Res?.profileRoot"
|
||||||
|
defaultProfileImage="assets/images/ico/img_nophoto.svg"
|
||||||
|
>
|
||||||
|
</ucap-organization-profile-image-01>
|
||||||
|
|
||||||
|
<div class="info-content" appProfileListItemUserInfo="info" *ngIf="!isShow">
|
||||||
|
<div
|
||||||
|
*ngIf="
|
||||||
|
!!userInfo && userInfo.nickName !== '';
|
||||||
|
then nicknameBlock;
|
||||||
|
else introBlock
|
||||||
|
"
|
||||||
|
></div>
|
||||||
|
<ng-template #nicknameBlock>{{ userInfo.nickName }}</ng-template>
|
||||||
|
<ng-template #introBlock>{{ userInfo.intro }}</ng-template>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="action-content"
|
||||||
|
appProfileListItemUserAction="action"
|
||||||
|
*ngIf="isShow && !isDialog"
|
||||||
|
>
|
||||||
|
<ng-template
|
||||||
|
[ngTemplateOutlet]="profileMoreContextTemplate"
|
||||||
|
></ng-template>
|
||||||
|
</div>
|
||||||
|
</ucap-organization-profile-list-item-02>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ng-template #profileMoreContextTemplate>
|
||||||
|
<button
|
||||||
|
mat-icon-button
|
||||||
|
aria-label="chat"
|
||||||
|
(click)="onClickProfileContextMenu($event, 'CHAT')"
|
||||||
|
>
|
||||||
|
<img src="../../../assets/images/ico/btn_lise_chat_a24.svg" alt="" />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
mat-icon-button
|
||||||
|
aria-label="message"
|
||||||
|
(click)="
|
||||||
|
$event.stopPropagation(); onClickProfileContextMenu($event, 'CHAT')
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<img src="../../../assets/images/ico/btn_list_message_a24.svg" alt="" />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
mat-icon-button
|
||||||
|
aria-label="mobile"
|
||||||
|
(click)="onClickProfileContextMenu($event, 'CHAT')"
|
||||||
|
>
|
||||||
|
<img src="../../../assets/images/ico/btn_list_mobile_a24.svg" alt="" />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
mat-icon-button
|
||||||
|
aria-label="call"
|
||||||
|
(click)="onClickProfileContextMenu($event, 'CHAT')"
|
||||||
|
>
|
||||||
|
<img src="../../../assets/images/ico/btn_list_call_a24.svg" alt="" />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
mat-icon-button
|
||||||
|
aria-label="vc"
|
||||||
|
(click)="onClickProfileContextMenu($event, 'CHAT')"
|
||||||
|
>
|
||||||
|
<img src="../../../assets/images/ico/btn_list_vc-a24.svg" alt="" />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
mat-icon-button
|
||||||
|
aria-label="more"
|
||||||
|
*ngIf="true"
|
||||||
|
(click)="onClickMore($event)"
|
||||||
|
>
|
||||||
|
<mat-icon>more_horiz</mat-icon>
|
||||||
|
</button>
|
||||||
|
</ng-template>
|
|
@ -0,0 +1,139 @@
|
||||||
|
@import '~@ucap/ng-ui-material/material';
|
||||||
|
|
||||||
|
/// var
|
||||||
|
/// --ucap-organization-profile-list-item-01-size: 70px
|
||||||
|
|
||||||
|
.ucap-group-profile-list-item-01-container {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0 16px;
|
||||||
|
height: 70px;
|
||||||
|
align-items: center;
|
||||||
|
&.line-top {
|
||||||
|
// border-top: 1px solid $gray-rec;
|
||||||
|
}
|
||||||
|
.user-profile-info {
|
||||||
|
display: inline-flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-grow: 2.3;
|
||||||
|
// .user-profile-thumb {
|
||||||
|
// @include profile-avatar-default(
|
||||||
|
// 0 5px 5px 0,
|
||||||
|
// 8,
|
||||||
|
// $green,
|
||||||
|
// 18px
|
||||||
|
// ); //오른 아래 공간, 모바일 온라인 아이콘 크기, 모바일 아이콘 색, 모바일 아이콘 bg크기
|
||||||
|
// .presence {
|
||||||
|
// //PC 상태
|
||||||
|
// @include presence-state(8px); //원크기
|
||||||
|
// }
|
||||||
|
// .profile-image {
|
||||||
|
// @include avatar-img(36px, 2px); //아바타 크기, 왼쪽공간
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
.user-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: flex-start;
|
||||||
|
padding-left: 16px;
|
||||||
|
.user-n-g {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row-reverse nowrap;
|
||||||
|
align-items: flex-end;
|
||||||
|
height: 22px;
|
||||||
|
.user-name {
|
||||||
|
@include ellipsis-column(1);
|
||||||
|
height: 22px;
|
||||||
|
font: {
|
||||||
|
size: 16px;
|
||||||
|
weight: 600;
|
||||||
|
}
|
||||||
|
// color: $gray-re21;
|
||||||
|
order: 1;
|
||||||
|
-ms-flex-order: 1;
|
||||||
|
}
|
||||||
|
.user-grade {
|
||||||
|
@include ellipsis(1);
|
||||||
|
align-self: stretch;
|
||||||
|
font: {
|
||||||
|
size: 13px;
|
||||||
|
}
|
||||||
|
// color: $gray-re70;
|
||||||
|
margin-left: 4px;
|
||||||
|
order: 0;
|
||||||
|
-ms-flex-order: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.dept-name {
|
||||||
|
@include ellipsis(1);
|
||||||
|
font-size: 12px;
|
||||||
|
// color: $gray-re6;
|
||||||
|
line-height: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.intro {
|
||||||
|
display: inline-flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
flex-basis: 35%;
|
||||||
|
flex-grow: 0;
|
||||||
|
align-items: baseline;
|
||||||
|
p {
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 1.4;
|
||||||
|
@include ellipsis(2);
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
&:before {
|
||||||
|
content: 'chat';
|
||||||
|
// @include font-family-ico($font-ico-default, 12, center, $lipstick);
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: flex-start;
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
line-height: 12px;
|
||||||
|
margin-right: 4.8px;
|
||||||
|
position: relative;
|
||||||
|
top: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.btn-partner-set {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0 25px;
|
||||||
|
border-top: 1px solid rgba(255, 255, 255, 0.8);
|
||||||
|
border-bottom: 1px solid rgba(255, 255, 255, 0.8);
|
||||||
|
height: 20px;
|
||||||
|
margin-top: 20px;
|
||||||
|
img {
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.intro-name {
|
||||||
|
display: inline-flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
flex-basis: 35%;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
overflow: hidden;
|
||||||
|
span {
|
||||||
|
display: inline-block;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 20px;
|
||||||
|
line-height: 20px;
|
||||||
|
// color: $gray-re70;
|
||||||
|
font-size: 11px;
|
||||||
|
padding: 0 10px;
|
||||||
|
border-radius: 30px;
|
||||||
|
// border: solid 1px $warm-pink;
|
||||||
|
background-color: #ffffff;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { By } from '@angular/platform-browser';
|
||||||
|
import { DebugElement } from '@angular/core';
|
||||||
|
|
||||||
|
import { ProfileListItemComponent } from './profile-list-item.component';
|
||||||
|
|
||||||
|
describe('ucap::ucap::organization::ProfileListItemComponent', () => {
|
||||||
|
let component: ProfileListItemComponent;
|
||||||
|
let fixture: ComponentFixture<ProfileListItemComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ProfileListItemComponent]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(ProfileListItemComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
157
src/app/ucap/group/components/profile-list-item-02.component.ts
Normal file
157
src/app/ucap/group/components/profile-list-item-02.component.ts
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
import {
|
||||||
|
Component,
|
||||||
|
OnInit,
|
||||||
|
OnDestroy,
|
||||||
|
ChangeDetectionStrategy,
|
||||||
|
ChangeDetectorRef,
|
||||||
|
Input,
|
||||||
|
EventEmitter,
|
||||||
|
Output,
|
||||||
|
ElementRef,
|
||||||
|
Self
|
||||||
|
} from '@angular/core';
|
||||||
|
import { GroupDetailData } from '@ucap/protocol-sync';
|
||||||
|
import { UserInfoSS, UserInfoF } from '@ucap/protocol-query';
|
||||||
|
|
||||||
|
import { I18nService } from '@ucap/ng-i18n';
|
||||||
|
import { ucapAnimations } from '@ucap/ng-ui';
|
||||||
|
import { Subject } from 'rxjs';
|
||||||
|
import { takeUntil } from 'rxjs/operators';
|
||||||
|
import { select, Store } from '@ngrx/store';
|
||||||
|
import {
|
||||||
|
ConfigurationSelector,
|
||||||
|
LoginSelector
|
||||||
|
} from '@ucap/ng-store-authentication';
|
||||||
|
import { VersionInfo2Response } from '@ucap/api-public';
|
||||||
|
import { LoginResponse } from '@ucap/protocol-authentication';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-group-profile-list-item-02',
|
||||||
|
templateUrl: './profile-list-item-02.component.html',
|
||||||
|
styleUrls: ['./profile-list-item-02.component.scss'],
|
||||||
|
animations: ucapAnimations,
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
|
})
|
||||||
|
export class ProfileListItem02Component implements OnInit, OnDestroy {
|
||||||
|
@Input()
|
||||||
|
userInfo: UserInfoF;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
group: GroupDetailData;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
checkable = false;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
isMe = false;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
checked = false;
|
||||||
|
|
||||||
|
@Output()
|
||||||
|
moreMenu: EventEmitter<{
|
||||||
|
event: MouseEvent;
|
||||||
|
userInfo: UserInfoF;
|
||||||
|
group: GroupDetailData;
|
||||||
|
rect: any;
|
||||||
|
}> = new EventEmitter();
|
||||||
|
|
||||||
|
@Output()
|
||||||
|
changeCheckUser: EventEmitter<{
|
||||||
|
checked: boolean;
|
||||||
|
userInfo: UserInfoF;
|
||||||
|
}> = new EventEmitter();
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
isShow = false;
|
||||||
|
@Input()
|
||||||
|
isDialog = false;
|
||||||
|
@Input()
|
||||||
|
isClickMore = false;
|
||||||
|
|
||||||
|
private ngOnDestroySubject: Subject<void>;
|
||||||
|
|
||||||
|
loginRes: LoginResponse;
|
||||||
|
versionInfo2Res: VersionInfo2Response;
|
||||||
|
|
||||||
|
tempRect: any;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private changeDetectorRef: ChangeDetectorRef,
|
||||||
|
private i18nService: I18nService,
|
||||||
|
@Self() private elementRef: ElementRef,
|
||||||
|
private store: Store<any>
|
||||||
|
) {
|
||||||
|
this.i18nService.setDefaultNamespace('organization');
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.ngOnDestroySubject = new Subject();
|
||||||
|
|
||||||
|
this.store
|
||||||
|
.pipe(
|
||||||
|
takeUntil(this.ngOnDestroySubject),
|
||||||
|
select(ConfigurationSelector.versionInfo2Response)
|
||||||
|
)
|
||||||
|
.subscribe((versionInfo2Res) => {
|
||||||
|
this.versionInfo2Res = versionInfo2Res;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.store
|
||||||
|
.pipe(takeUntil(this.ngOnDestroySubject), select(LoginSelector.loginRes))
|
||||||
|
.subscribe((loginRes) => {
|
||||||
|
this.loginRes = loginRes;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.tempRect = this.elementRef.nativeElement.getBoundingClientRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
if (!!this.ngOnDestroySubject) {
|
||||||
|
this.ngOnDestroySubject.next();
|
||||||
|
this.ngOnDestroySubject.complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onOpenProfile(userInfo: UserInfoSS): void {
|
||||||
|
alert('Open Profile');
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeCheckUser(param: { checked: boolean; userInfo: UserInfoF }) {
|
||||||
|
this.changeCheckUser.emit(param);
|
||||||
|
}
|
||||||
|
|
||||||
|
onMouseover(event: MouseEvent): void {
|
||||||
|
if (!this.isMe && !this.isDialog) {
|
||||||
|
this.isShow = true;
|
||||||
|
}
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
onMouseleave(event: MouseEvent): void {
|
||||||
|
if (!this.isMe && !this.isDialog) {
|
||||||
|
this.isShow = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickProfileContextMenu(event: MouseEvent, type: string) {}
|
||||||
|
|
||||||
|
onClickMore(event: MouseEvent) {
|
||||||
|
this.isClickMore = true;
|
||||||
|
|
||||||
|
const rect = this.elementRef.nativeElement.getBoundingClientRect();
|
||||||
|
|
||||||
|
this.moreMenu.emit({
|
||||||
|
event,
|
||||||
|
userInfo: this.userInfo,
|
||||||
|
group: this.group,
|
||||||
|
rect
|
||||||
|
});
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
}
|
21
src/app/ucap/group/components/profile-list.component.html
Normal file
21
src/app/ucap/group/components/profile-list.component.html
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<div class="profile-list-container">
|
||||||
|
<ucap-organization-profile-list [userInfos]="userInfos">
|
||||||
|
<ng-template ucapOrganizationProfileListNode let-userInfo>
|
||||||
|
<app-group-profile-list-item-02
|
||||||
|
[userInfo]="userInfo"
|
||||||
|
[checkable]="checkable"
|
||||||
|
[isDialog]="isDialog"
|
||||||
|
[checked]="getCheckedUser(userInfo)"
|
||||||
|
(openProfile)="onOpenProfile($event)"
|
||||||
|
(changeCheckUser)="onChangeCheckUser($event)"
|
||||||
|
>
|
||||||
|
<ucap-organization-profile-image-01
|
||||||
|
ucapOrganizationProfileListItem01="profileImage"
|
||||||
|
[userInfo]="userInfo"
|
||||||
|
[profileImageRoot]="versionInfo2Res?.profileRoot"
|
||||||
|
defaultProfileImage="assets/images/ico/img_nophoto.svg"
|
||||||
|
></ucap-organization-profile-image-01>
|
||||||
|
</app-group-profile-list-item-02>
|
||||||
|
</ng-template>
|
||||||
|
</ucap-organization-profile-list>
|
||||||
|
</div>
|
|
@ -0,0 +1,4 @@
|
||||||
|
.profile-list-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
32
src/app/ucap/group/components/profile-list.component.spec.ts
Normal file
32
src/app/ucap/group/components/profile-list.component.spec.ts
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
import { TestBed, async } from '@angular/core/testing';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { Profile01Component } from './profile-01.component';
|
||||||
|
|
||||||
|
describe('app::ucap::organization::Profile01Component', () => {
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [RouterTestingModule],
|
||||||
|
declarations: [Profile01Component]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should create the app', () => {
|
||||||
|
const fixture = TestBed.createComponent(Profile01Component);
|
||||||
|
const app = fixture.componentInstance;
|
||||||
|
expect(app).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should have as title 'ucap-lg-web'`, () => {
|
||||||
|
const fixture = TestBed.createComponent(Profile01Component);
|
||||||
|
const app = fixture.componentInstance;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render title', () => {
|
||||||
|
const fixture = TestBed.createComponent(Profile01Component);
|
||||||
|
fixture.detectChanges();
|
||||||
|
const compiled = fixture.nativeElement;
|
||||||
|
expect(compiled.querySelector('.content span').textContent).toContain(
|
||||||
|
'ucap-lg-web app is running!'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
207
src/app/ucap/group/components/profile-list.component.ts
Normal file
207
src/app/ucap/group/components/profile-list.component.ts
Normal file
|
@ -0,0 +1,207 @@
|
||||||
|
import { Subject, of } from 'rxjs';
|
||||||
|
import { takeUntil, take, map, catchError } from 'rxjs/operators';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Component,
|
||||||
|
OnInit,
|
||||||
|
OnDestroy,
|
||||||
|
ChangeDetectionStrategy,
|
||||||
|
ChangeDetectorRef,
|
||||||
|
Input,
|
||||||
|
Output,
|
||||||
|
EventEmitter
|
||||||
|
} from '@angular/core';
|
||||||
|
|
||||||
|
import { Store, select } from '@ngrx/store';
|
||||||
|
|
||||||
|
import { VersionInfo2Response } from '@ucap/api-public';
|
||||||
|
import { LoginResponse } from '@ucap/protocol-authentication';
|
||||||
|
import {
|
||||||
|
AuthResponse,
|
||||||
|
UserInfoSS,
|
||||||
|
DeptSearchType,
|
||||||
|
DeptUserRequest
|
||||||
|
} from '@ucap/protocol-query';
|
||||||
|
|
||||||
|
import { LogService } from '@ucap/ng-logger';
|
||||||
|
import {
|
||||||
|
LoginSelector,
|
||||||
|
AuthorizationSelector,
|
||||||
|
ConfigurationSelector
|
||||||
|
} from '@ucap/ng-store-authentication';
|
||||||
|
import { QueryProtocolService } from '@ucap/ng-protocol-query';
|
||||||
|
import {
|
||||||
|
DepartmentSelector,
|
||||||
|
PresenceActions
|
||||||
|
} from '@ucap/ng-store-organization';
|
||||||
|
import {
|
||||||
|
FixedSizeVirtualScrollStrategy,
|
||||||
|
VIRTUAL_SCROLL_STRATEGY
|
||||||
|
} from '@angular/cdk/scrolling';
|
||||||
|
|
||||||
|
import { SearchData } from '@app/ucap/organization/models/search-data';
|
||||||
|
|
||||||
|
export class ProfileListVirtualScrollStrategy extends FixedSizeVirtualScrollStrategy {
|
||||||
|
constructor() {
|
||||||
|
super(70, 250, 500); // (itemSize, minBufferPx, maxBufferPx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-group-profile-list',
|
||||||
|
templateUrl: './profile-list.component.html',
|
||||||
|
styleUrls: ['./profile-list.component.scss'],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: VIRTUAL_SCROLL_STRATEGY,
|
||||||
|
useClass: ProfileListVirtualScrollStrategy
|
||||||
|
}
|
||||||
|
],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
|
})
|
||||||
|
export class ProfileListComponent implements OnInit, OnDestroy {
|
||||||
|
@Input()
|
||||||
|
checkable = false;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
isDialog = false;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
set searchData(data: SearchData) {
|
||||||
|
if (!this.loginRes) {
|
||||||
|
this._searchData = data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.searchMember(data);
|
||||||
|
}
|
||||||
|
// tslint:disable-next-line: variable-name
|
||||||
|
private _searchData: SearchData;
|
||||||
|
|
||||||
|
@Input() selectedUser: UserInfoSS[];
|
||||||
|
|
||||||
|
@Output()
|
||||||
|
searched: EventEmitter<UserInfoSS[]> = new EventEmitter();
|
||||||
|
|
||||||
|
@Output()
|
||||||
|
toggleCheck: EventEmitter<{
|
||||||
|
checked: boolean;
|
||||||
|
userInfo: UserInfoSS;
|
||||||
|
}> = new EventEmitter();
|
||||||
|
|
||||||
|
set userInfos(userInfos: UserInfoSS[]) {
|
||||||
|
this._userInfos = userInfos;
|
||||||
|
this.searched.emit(userInfos);
|
||||||
|
}
|
||||||
|
get userInfos() {
|
||||||
|
return this._userInfos;
|
||||||
|
}
|
||||||
|
// tslint:disable-next-line: variable-name
|
||||||
|
_userInfos: UserInfoSS[] = [];
|
||||||
|
|
||||||
|
loginRes: LoginResponse;
|
||||||
|
versionInfo2Res: VersionInfo2Response;
|
||||||
|
|
||||||
|
processing = false;
|
||||||
|
|
||||||
|
private ngOnDestroySubject: Subject<void>;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private queryProtocolService: QueryProtocolService,
|
||||||
|
private store: Store<any>,
|
||||||
|
private changeDetectorRef: ChangeDetectorRef,
|
||||||
|
private logService: LogService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.ngOnDestroySubject = new Subject();
|
||||||
|
|
||||||
|
this.store
|
||||||
|
.pipe(
|
||||||
|
takeUntil(this.ngOnDestroySubject),
|
||||||
|
select(ConfigurationSelector.versionInfo2Response)
|
||||||
|
)
|
||||||
|
.subscribe((versionInfo2Res) => {
|
||||||
|
this.versionInfo2Res = versionInfo2Res;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.store
|
||||||
|
.pipe(takeUntil(this.ngOnDestroySubject), select(LoginSelector.loginRes))
|
||||||
|
.subscribe((loginRes) => {
|
||||||
|
this.loginRes = loginRes;
|
||||||
|
if (!!this._searchData) {
|
||||||
|
this.searchMember(this._searchData);
|
||||||
|
this._searchData = undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
if (!!this.ngOnDestroySubject) {
|
||||||
|
this.ngOnDestroySubject.complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 개별 체크여부 */
|
||||||
|
getCheckedUser(userInfo: UserInfoSS) {
|
||||||
|
if (!!this.selectedUser && this.selectedUser.length > 0) {
|
||||||
|
return (
|
||||||
|
this.selectedUser.filter((item) => item.seq === userInfo.seq).length > 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 개별선택(토글) 이벤트 */
|
||||||
|
onChangeCheckUser(param: { checked: boolean; userInfo: UserInfoSS }) {
|
||||||
|
this.toggleCheck.emit(param);
|
||||||
|
}
|
||||||
|
|
||||||
|
onOpenProfile(userInfo: UserInfoSS): void {
|
||||||
|
alert('Open Profile');
|
||||||
|
}
|
||||||
|
|
||||||
|
private searchMember(searchData: SearchData) {
|
||||||
|
if (!searchData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const req = {
|
||||||
|
divCd: 'ORGS',
|
||||||
|
companyCode: searchData.companyCode,
|
||||||
|
searchRange: DeptSearchType.All,
|
||||||
|
search: searchData.searchWord,
|
||||||
|
senderCompanyCode: this.loginRes.userInfo.companyCode,
|
||||||
|
senderEmployeeType: this.loginRes.userInfo.employeeType
|
||||||
|
} as DeptUserRequest;
|
||||||
|
|
||||||
|
this.processing = true;
|
||||||
|
this.queryProtocolService
|
||||||
|
.deptUser(req)
|
||||||
|
.pipe(take(1))
|
||||||
|
.subscribe(
|
||||||
|
(data) => {
|
||||||
|
this.userInfos = data.userInfos.sort((a, b) =>
|
||||||
|
a.name < b.name ? -1 : a.name > b.name ? 1 : 0
|
||||||
|
);
|
||||||
|
this.changeDetectorRef.detectChanges();
|
||||||
|
|
||||||
|
// 검색 결과에 따른 프레즌스 조회.
|
||||||
|
const userSeqList: string[] = [];
|
||||||
|
this.userInfos.map((user) => userSeqList.push(user.seq));
|
||||||
|
|
||||||
|
if (userSeqList.length > 0) {
|
||||||
|
this.store.dispatch(
|
||||||
|
PresenceActions.bulkInfo({
|
||||||
|
divCd: 'orgSrch',
|
||||||
|
userSeqs: userSeqList
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(error) => {},
|
||||||
|
() => {
|
||||||
|
this.processing = false;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,7 +6,7 @@
|
||||||
[checkable]="loginRes?.userSeq !== userInfo.seq"
|
[checkable]="loginRes?.userSeq !== userInfo.seq"
|
||||||
[checked]="getCheckedUser(userInfo)"
|
[checked]="getCheckedUser(userInfo)"
|
||||||
(openProfile)="onOpenProfile($event)"
|
(openProfile)="onOpenProfile($event)"
|
||||||
(changeCheck)="onToggleUser($event)"
|
(changeCheck)="onChangeCheckUser($event)"
|
||||||
>
|
>
|
||||||
<ucap-organization-profile-image-01
|
<ucap-organization-profile-image-01
|
||||||
ucapOrganizationProfileListItem01="profileImage"
|
ucapOrganizationProfileListItem01="profileImage"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Subject, of } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
import { takeUntil, take, map, catchError } from 'rxjs/operators';
|
import { takeUntil, take } from 'rxjs/operators';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Component,
|
Component,
|
||||||
|
@ -7,91 +7,115 @@ import {
|
||||||
OnDestroy,
|
OnDestroy,
|
||||||
ChangeDetectionStrategy,
|
ChangeDetectionStrategy,
|
||||||
ChangeDetectorRef,
|
ChangeDetectorRef,
|
||||||
Input
|
Input,
|
||||||
|
Output,
|
||||||
|
EventEmitter
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
|
|
||||||
import { Store, select } from '@ngrx/store';
|
import { Store, select } from '@ngrx/store';
|
||||||
|
|
||||||
import { VersionInfo2Response } from '@ucap/api-public';
|
import { VersionInfo2Response } from '@ucap/api-public';
|
||||||
import { LoginResponse } from '@ucap/protocol-authentication';
|
import { LoginResponse } from '@ucap/protocol-authentication';
|
||||||
import { AuthResponse, UserInfoSS, DeptSearchType } from '@ucap/protocol-query';
|
import {
|
||||||
|
UserInfoSS,
|
||||||
|
DeptSearchType,
|
||||||
|
DeptUserRequest
|
||||||
|
} from '@ucap/protocol-query';
|
||||||
|
|
||||||
import { LogService } from '@ucap/ng-logger';
|
import { LogService } from '@ucap/ng-logger';
|
||||||
import {
|
import {
|
||||||
LoginSelector,
|
LoginSelector,
|
||||||
AuthorizationSelector,
|
|
||||||
ConfigurationSelector
|
ConfigurationSelector
|
||||||
} from '@ucap/ng-store-authentication';
|
} from '@ucap/ng-store-authentication';
|
||||||
import { QueryProtocolService } from '@ucap/ng-protocol-query';
|
import { QueryProtocolService } from '@ucap/ng-protocol-query';
|
||||||
import {
|
import {
|
||||||
|
DepartmentActions,
|
||||||
DepartmentSelector,
|
DepartmentSelector,
|
||||||
PresenceActions
|
PresenceActions
|
||||||
} from '@ucap/ng-store-organization';
|
} from '@ucap/ng-store-organization';
|
||||||
|
import {
|
||||||
|
FixedSizeVirtualScrollStrategy,
|
||||||
|
VIRTUAL_SCROLL_STRATEGY
|
||||||
|
} from '@angular/cdk/scrolling';
|
||||||
|
|
||||||
|
import { SearchData } from '../models/search-data';
|
||||||
|
import { SortOrder } from '@ucap/core';
|
||||||
|
|
||||||
|
export class ProfileListVirtualScrollStrategy extends FixedSizeVirtualScrollStrategy {
|
||||||
|
constructor() {
|
||||||
|
super(70, 250, 500); // (itemSize, minBufferPx, maxBufferPx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CheckedInfo {
|
||||||
|
checked: boolean;
|
||||||
|
userInfo: UserInfoSS;
|
||||||
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-organization-profile-list',
|
selector: 'app-organization-profile-list',
|
||||||
templateUrl: './profile-list.component.html',
|
templateUrl: './profile-list.component.html',
|
||||||
styleUrls: ['./profile-list.component.scss'],
|
styleUrls: ['./profile-list.component.scss'],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: VIRTUAL_SCROLL_STRATEGY,
|
||||||
|
useClass: ProfileListVirtualScrollStrategy
|
||||||
|
}
|
||||||
|
],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class ProfileListComponent implements OnInit, OnDestroy {
|
export class ProfileListComponent implements OnInit, OnDestroy {
|
||||||
@Input()
|
@Input()
|
||||||
set searchData(data: {
|
set searchData(data: SearchData) {
|
||||||
companyCode: string;
|
|
||||||
searchWord: string;
|
|
||||||
isSearch: boolean;
|
|
||||||
}) {
|
|
||||||
if (!this.loginRes) {
|
if (!this.loginRes) {
|
||||||
|
this._searchData = data;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.processing = true;
|
this.searchMember(data);
|
||||||
|
|
||||||
this.queryProtocolService
|
|
||||||
.deptUser({
|
|
||||||
divCd: 'ORGS',
|
|
||||||
companyCode: data.companyCode,
|
|
||||||
searchRange: DeptSearchType.All,
|
|
||||||
search: data.searchWord,
|
|
||||||
senderCompanyCode: this.loginRes.userInfo.companyCode,
|
|
||||||
senderEmployeeType: this.loginRes.userInfo.employeeType
|
|
||||||
})
|
|
||||||
.pipe(take(1))
|
|
||||||
.subscribe(
|
|
||||||
(res) => {
|
|
||||||
// 검색 결과 처리.
|
|
||||||
this.userInfos = res.userInfos.sort((a, b) =>
|
|
||||||
a.name < b.name ? -1 : a.name > b.name ? 1 : 0
|
|
||||||
);
|
|
||||||
this.changeDetectorRef.detectChanges();
|
|
||||||
|
|
||||||
// 검색 결과에 따른 프레즌스 조회.
|
|
||||||
const userSeqList: string[] = [];
|
|
||||||
this.userInfos.map((user) => userSeqList.push(user.seq));
|
|
||||||
|
|
||||||
if (userSeqList.length > 0) {
|
|
||||||
this.store.dispatch(
|
|
||||||
PresenceActions.bulkInfo({
|
|
||||||
divCd: 'orgSrch',
|
|
||||||
userSeqs: userSeqList
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
},
|
// tslint:disable-next-line: variable-name
|
||||||
(error) => {},
|
private _searchData: SearchData;
|
||||||
() => {
|
|
||||||
this.processing = false;
|
@Input()
|
||||||
|
selectedUser: UserInfoSS[];
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
set sortOrder(value: SortOrder) {
|
||||||
|
this._sortOrder = value;
|
||||||
|
this.userInfos = this.sort(this.userInfos);
|
||||||
}
|
}
|
||||||
);
|
get sortOrder() {
|
||||||
|
return this._sortOrder;
|
||||||
}
|
}
|
||||||
|
// tslint:disable-next-line: variable-name
|
||||||
|
_sortOrder: SortOrder = {
|
||||||
|
property: 'name',
|
||||||
|
ascending: true
|
||||||
|
};
|
||||||
|
|
||||||
|
@Output()
|
||||||
|
searched: EventEmitter<UserInfoSS[]> = new EventEmitter();
|
||||||
|
|
||||||
|
@Output()
|
||||||
|
changedCheck: EventEmitter<CheckedInfo[]> = new EventEmitter();
|
||||||
|
|
||||||
|
set userInfos(userInfos: UserInfoSS[]) {
|
||||||
|
this._userInfos = userInfos;
|
||||||
|
this.searched.emit(userInfos);
|
||||||
|
}
|
||||||
|
get userInfos() {
|
||||||
|
return this._userInfos;
|
||||||
|
}
|
||||||
|
// tslint:disable-next-line: variable-name
|
||||||
|
_userInfos: UserInfoSS[] = [];
|
||||||
|
|
||||||
loginRes: LoginResponse;
|
loginRes: LoginResponse;
|
||||||
versionInfo2Res: VersionInfo2Response;
|
versionInfo2Res: VersionInfo2Response;
|
||||||
|
|
||||||
userInfos: UserInfoSS[] = [];
|
|
||||||
selectedUserInfos: UserInfoSS[] = [];
|
|
||||||
processing = false;
|
processing = false;
|
||||||
|
|
||||||
private ngOnDestroySubject: Subject<void>;
|
private ngOnDestroySubject: Subject<void>;
|
||||||
|
private myDeptDestroySubject: Subject<void>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private queryProtocolService: QueryProtocolService,
|
private queryProtocolService: QueryProtocolService,
|
||||||
|
@ -116,6 +140,10 @@ export class ProfileListComponent implements OnInit, OnDestroy {
|
||||||
.pipe(takeUntil(this.ngOnDestroySubject), select(LoginSelector.loginRes))
|
.pipe(takeUntil(this.ngOnDestroySubject), select(LoginSelector.loginRes))
|
||||||
.subscribe((loginRes) => {
|
.subscribe((loginRes) => {
|
||||||
this.loginRes = loginRes;
|
this.loginRes = loginRes;
|
||||||
|
if (!!this._searchData) {
|
||||||
|
this.searchMember(this._searchData);
|
||||||
|
this._searchData = undefined;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,36 +153,156 @@ export class ProfileListComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkAll() {
|
||||||
|
if (!this.userInfos || 0 === this.userInfos.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const checked: CheckedInfo[] = [];
|
||||||
|
this.userInfos.forEach((u) => {
|
||||||
|
checked.push({
|
||||||
|
checked: true,
|
||||||
|
userInfo: u
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.changedCheck.emit(checked);
|
||||||
|
}
|
||||||
|
|
||||||
/** 개별 체크여부 */
|
/** 개별 체크여부 */
|
||||||
getCheckedUser(userInfo: UserInfoSS) {
|
getCheckedUser(userInfo: UserInfoSS) {
|
||||||
if (!!this.selectedUserInfos && this.selectedUserInfos.length > 0) {
|
if (!!this.selectedUser && this.selectedUser.length > 0) {
|
||||||
return (
|
return (
|
||||||
this.selectedUserInfos.filter((item) => item.seq === userInfo.seq)
|
this.selectedUser.filter((item) => item.seq === userInfo.seq).length > 0
|
||||||
.length > 0
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 개별선택(토글) 이벤트 */
|
/** 개별선택(토글) 이벤트 */
|
||||||
onToggleUser(param: { isChecked: boolean; userInfo: UserInfoSS }) {
|
onChangeCheckUser(param: { checked: boolean; userInfo: UserInfoSS }) {
|
||||||
if (!this.loginRes || param.userInfo.seq === this.loginRes.userSeq) {
|
this.changedCheck.emit([param]);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
!this.selectedUserInfos.some((user) => user.seq === param.userInfo.seq)
|
|
||||||
) {
|
|
||||||
this.selectedUserInfos = [...this.selectedUserInfos, param.userInfo];
|
|
||||||
} else {
|
|
||||||
this.selectedUserInfos = this.selectedUserInfos.filter(
|
|
||||||
(item) => item.seq !== param.userInfo.seq
|
|
||||||
);
|
|
||||||
}
|
|
||||||
this.changeDetectorRef.detectChanges();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onOpenProfile(userInfo: UserInfoSS): void {
|
onOpenProfile(userInfo: UserInfoSS): void {
|
||||||
alert('Open Profile');
|
alert('Open Profile');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getMyDeptMember() {
|
||||||
|
this.myDeptDestroySubject = new Subject();
|
||||||
|
|
||||||
|
const req: DeptUserRequest = {
|
||||||
|
divCd: 'ORG',
|
||||||
|
companyCode: this.loginRes.companyCode,
|
||||||
|
seq: this.loginRes.departmentCode,
|
||||||
|
search: '',
|
||||||
|
searchRange: DeptSearchType.All,
|
||||||
|
senderCompanyCode: this.loginRes.companyCode,
|
||||||
|
senderEmployeeType: this.loginRes.userInfo.employeeType
|
||||||
|
};
|
||||||
|
|
||||||
|
this.store
|
||||||
|
.pipe(
|
||||||
|
takeUntil(this.ngOnDestroySubject),
|
||||||
|
select(DepartmentSelector.myDepartmentUserInfoList)
|
||||||
|
)
|
||||||
|
.subscribe(
|
||||||
|
(myDepartmentUserInfoList) => {
|
||||||
|
if (!myDepartmentUserInfoList) {
|
||||||
|
this.store.dispatch(DepartmentActions.myDeptUser({ req }));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.userInfos = this.sort(myDepartmentUserInfoList);
|
||||||
|
|
||||||
|
this.myDeptDestroySubject.next();
|
||||||
|
this.myDeptDestroySubject.complete();
|
||||||
|
this.myDeptDestroySubject = undefined;
|
||||||
|
},
|
||||||
|
(error) => {},
|
||||||
|
() => {}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private sort(userInfos: UserInfoSS[]): UserInfoSS[] {
|
||||||
|
if (!userInfos || 0 === userInfos.length) {
|
||||||
|
return userInfos;
|
||||||
|
}
|
||||||
|
|
||||||
|
const property = this.sortOrder.property;
|
||||||
|
const ascending = this.sortOrder.ascending;
|
||||||
|
|
||||||
|
return userInfos.slice().sort((a, b) => {
|
||||||
|
let c: any;
|
||||||
|
let d: any;
|
||||||
|
try {
|
||||||
|
c = ascending ? a[property] : b[property];
|
||||||
|
d = ascending ? b[property] : a[property];
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
return c < d ? -1 : c > d ? 1 : 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private searchMember(searchData: SearchData) {
|
||||||
|
if (!searchData || (!searchData.companyCode && !searchData.deptSeq)) {
|
||||||
|
this.getMyDeptMember();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!!this.myDeptDestroySubject) {
|
||||||
|
this.myDeptDestroySubject.next();
|
||||||
|
this.myDeptDestroySubject.complete();
|
||||||
|
this.myDeptDestroySubject = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
let req: DeptUserRequest;
|
||||||
|
if (searchData.bySearch) {
|
||||||
|
req = {
|
||||||
|
divCd: 'ORGS',
|
||||||
|
companyCode: searchData.companyCode,
|
||||||
|
searchRange: DeptSearchType.All,
|
||||||
|
search: searchData.searchWord,
|
||||||
|
senderCompanyCode: this.loginRes.userInfo.companyCode,
|
||||||
|
senderEmployeeType: this.loginRes.userInfo.employeeType
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
req = {
|
||||||
|
divCd: 'ORG',
|
||||||
|
companyCode: this.loginRes.companyCode,
|
||||||
|
seq: Number(searchData.deptSeq),
|
||||||
|
search: '',
|
||||||
|
searchRange: DeptSearchType.All,
|
||||||
|
senderCompanyCode: this.loginRes.companyCode,
|
||||||
|
senderEmployeeType: this.loginRes.userInfo.employeeType
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
this.processing = true;
|
||||||
|
this.queryProtocolService
|
||||||
|
.deptUser(req)
|
||||||
|
.pipe(take(1))
|
||||||
|
.subscribe(
|
||||||
|
(data) => {
|
||||||
|
this.userInfos = this.sort(data.userInfos);
|
||||||
|
this.changeDetectorRef.detectChanges();
|
||||||
|
|
||||||
|
// 검색 결과에 따른 프레즌스 조회.
|
||||||
|
const userSeqList: string[] = [];
|
||||||
|
this.userInfos.map((user) => userSeqList.push(user.seq));
|
||||||
|
|
||||||
|
if (userSeqList.length > 0) {
|
||||||
|
this.store.dispatch(
|
||||||
|
PresenceActions.bulkInfo({
|
||||||
|
divCd: 'orgSrch',
|
||||||
|
userSeqs: userSeqList
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(error) => {},
|
||||||
|
() => {
|
||||||
|
this.processing = false;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
<div class="search-container">
|
<div class="search-container">
|
||||||
<ucap-organization-search-for-tenant
|
<ucap-organization-search-for-tenant
|
||||||
[companyList]="companyList"
|
[companyList]="companyList"
|
||||||
[defaultCompany]="defaultCompany"
|
[defaultCompany]="searchData.companyCode"
|
||||||
|
[defaultSearchWord]="searchData.searchWord"
|
||||||
placeholder="이름 부서명, 전화번호, 이메일"
|
placeholder="이름 부서명, 전화번호, 이메일"
|
||||||
(changed)="onChanged($event)"
|
(changed)="onChanged($event)"
|
||||||
(canceled)="onCanceled()"
|
(canceled)="onCanceled()"
|
||||||
|
|
|
@ -8,7 +8,8 @@ import {
|
||||||
ChangeDetectionStrategy,
|
ChangeDetectionStrategy,
|
||||||
ChangeDetectorRef,
|
ChangeDetectorRef,
|
||||||
Output,
|
Output,
|
||||||
EventEmitter
|
EventEmitter,
|
||||||
|
Input
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
|
|
||||||
import { Store, select } from '@ngrx/store';
|
import { Store, select } from '@ngrx/store';
|
||||||
|
@ -19,6 +20,8 @@ import { LogService } from '@ucap/ng-logger';
|
||||||
import { CompanySelector } from '@ucap/ng-store-organization';
|
import { CompanySelector } from '@ucap/ng-store-organization';
|
||||||
|
|
||||||
import { AppAuthenticationService } from '@app/services/app-authentication.service';
|
import { AppAuthenticationService } from '@app/services/app-authentication.service';
|
||||||
|
import { SearchData } from '../models/search-data';
|
||||||
|
import { UserStore } from '@app/models/user-store';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-organization-search-for-tenant',
|
selector: 'app-organization-search-for-tenant',
|
||||||
|
@ -27,34 +30,45 @@ import { AppAuthenticationService } from '@app/services/app-authentication.servi
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class SearchForTenantComponent implements OnInit, OnDestroy {
|
export class SearchForTenantComponent implements OnInit, OnDestroy {
|
||||||
@Output()
|
@Output() searchDataChange: EventEmitter<SearchData> = new EventEmitter();
|
||||||
changed: EventEmitter<{
|
@Input() set searchData(value: SearchData) {
|
||||||
isShowSearch: boolean;
|
this._searchData = value;
|
||||||
companyCode: string;
|
if (!this._searchData) {
|
||||||
searchWord: string;
|
this._searchData = {
|
||||||
}> = new EventEmitter();
|
companyCode: this.userStore.companyCode
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
if (!this._searchData.companyCode) {
|
||||||
|
this._searchData.companyCode = this.userStore.companyCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get searchData() {
|
||||||
|
return this._searchData;
|
||||||
|
}
|
||||||
|
// tslint:disable-next-line: variable-name
|
||||||
|
_searchData: SearchData;
|
||||||
|
|
||||||
@Output()
|
@Output()
|
||||||
canceled: EventEmitter<void> = new EventEmitter();
|
canceled: EventEmitter<void> = new EventEmitter();
|
||||||
|
|
||||||
companyList: Company[];
|
companyList: Company[];
|
||||||
defaultCompany: string;
|
|
||||||
|
|
||||||
private ngOnDestroySubject = new Subject<boolean>();
|
private ngOnDestroySubject = new Subject<boolean>();
|
||||||
|
private userStore: UserStore;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private appAuthenticationService: AppAuthenticationService,
|
private appAuthenticationService: AppAuthenticationService,
|
||||||
private store: Store<any>,
|
private store: Store<any>,
|
||||||
private changeDetectorRef: ChangeDetectorRef,
|
private changeDetectorRef: ChangeDetectorRef,
|
||||||
private logService: LogService
|
private logService: LogService
|
||||||
) {}
|
) {
|
||||||
|
this.userStore = this.appAuthenticationService.getUserStore();
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.ngOnDestroySubject = new Subject<boolean>();
|
this.ngOnDestroySubject = new Subject<boolean>();
|
||||||
|
|
||||||
const userStore = this.appAuthenticationService.getUserStore();
|
|
||||||
this.defaultCompany = userStore.companyCode;
|
|
||||||
|
|
||||||
this.store
|
this.store
|
||||||
.pipe(
|
.pipe(
|
||||||
takeUntil(this.ngOnDestroySubject),
|
takeUntil(this.ngOnDestroySubject),
|
||||||
|
@ -72,15 +86,14 @@ export class SearchForTenantComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
onChanged(data: { companyCode: string; searchWord: string }): void {
|
onChanged(data: { companyCode: string; searchWord: string }): void {
|
||||||
this.changed.emit({
|
this.searchDataChange.emit({
|
||||||
...data,
|
companyCode: data.companyCode,
|
||||||
isShowSearch: true
|
searchWord: data.searchWord
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onCanceled(): void {
|
onCanceled(): void {
|
||||||
this.changed.emit({
|
this.searchDataChange.emit({
|
||||||
isShowSearch: false,
|
|
||||||
companyCode: '',
|
companyCode: '',
|
||||||
searchWord: ''
|
searchWord: ''
|
||||||
});
|
});
|
||||||
|
|
|
@ -53,7 +53,7 @@ export class TreeComponent implements OnInit, OnDestroy {
|
||||||
@Input()
|
@Input()
|
||||||
set initialExpanded(seq: number) {
|
set initialExpanded(seq: number) {
|
||||||
if (!!this.treeData) {
|
if (!!this.treeData) {
|
||||||
this.treeList.expand(seq);
|
this.expand(seq);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._initialExpanded = seq;
|
this._initialExpanded = seq;
|
||||||
|
|
6
src/app/ucap/organization/models/search-data.ts
Normal file
6
src/app/ucap/organization/models/search-data.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
export interface SearchData {
|
||||||
|
deptSeq?: string;
|
||||||
|
companyCode?: string;
|
||||||
|
searchWord?: string;
|
||||||
|
bySearch?: boolean;
|
||||||
|
}
|
|
@ -6,13 +6,10 @@
|
||||||
"openRoom": "Open room",
|
"openRoom": "Open room",
|
||||||
"turnOnRoomAlert": "Turn on room alert",
|
"turnOnRoomAlert": "Turn on room alert",
|
||||||
"turnOffRoomAlert": "Turn off room alert",
|
"turnOffRoomAlert": "Turn off room alert",
|
||||||
"exitFromRoom": "Exit room",
|
"exitFromRoom": "Exit room"
|
||||||
"dialog": {
|
|
||||||
"titleExitFromRoom": "Exit room",
|
|
||||||
"confirmExitFromRoom": "Do you want to exit the chat room?<br/>Exiting will delete your chat history and chat room information."
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"label": {
|
"label": {
|
||||||
|
"chat": "Chat",
|
||||||
"menu": "Menu",
|
"menu": "Menu",
|
||||||
"search": "Search",
|
"search": "Search",
|
||||||
"notificationIsOn": "Notification is on",
|
"notificationIsOn": "Notification is on",
|
||||||
|
@ -26,5 +23,51 @@
|
||||||
"emailSend": "Send email for chat.",
|
"emailSend": "Send email for chat.",
|
||||||
"translation": "Trnaslation",
|
"translation": "Trnaslation",
|
||||||
"gams": "+GAMS"
|
"gams": "+GAMS"
|
||||||
|
},
|
||||||
|
"event": {
|
||||||
|
"inviteToRoomWith": "{{owner}} invited {{inviter}}.",
|
||||||
|
"exitFromRoomWith": "{{exitor}} has left.",
|
||||||
|
"ejectedFromRoomWith": "{{requester}} has eject {{ejected}}.",
|
||||||
|
"renamedRoomWith": "{{requester}} has changed their chat room name to '{{roomName}}'.",
|
||||||
|
"setTimerWith": "{{requester}} set a timer ({{timer}})",
|
||||||
|
"iosCapture": "{{requester}} captured a conversation",
|
||||||
|
"showMassTranslationOfOriginal": "Show original",
|
||||||
|
"showMassTranslationOfTranslated": "Show translated",
|
||||||
|
"showMassDetail": "Show detail",
|
||||||
|
"readToHere": "Read to here",
|
||||||
|
"recalled": "Recalled",
|
||||||
|
"scheduleTypeNew": "[Event] Registered",
|
||||||
|
"scheduleTypeUpdate": "[Event] Modified",
|
||||||
|
"scheduleTypeDelete": "[Event] Deleted",
|
||||||
|
"scheduleTypeDefault": "[Event] Processing..",
|
||||||
|
"scheduleTypePrefix": "[Event] ",
|
||||||
|
"scheduleTypeSurfixLeft": " left",
|
||||||
|
"showPreviousEvents": "Show previous",
|
||||||
|
"moreUnreadEventsWith": "There is unread messages<span class=\"text-warn-color\">({{countOfUnread}})</span>"
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"label": "Chat erros",
|
||||||
|
"inputChatMessage": "Please enter a chat message",
|
||||||
|
"maxLengthOfMassText": "If you include a sticker, you can't send more than {{maxLength}} characters.",
|
||||||
|
"maxCountOfRoomMemberWith": "you can't open room with more than {{maxCount}} peoples.",
|
||||||
|
"emptyOpenRoomType": "Pleas select type of room",
|
||||||
|
"translateServerError": "Failed to translate"
|
||||||
|
},
|
||||||
|
"dialog": {
|
||||||
|
"title": {
|
||||||
|
"exitFromRoom": "Exit room",
|
||||||
|
"newChatRoom": "Add new chat room"
|
||||||
|
},
|
||||||
|
"confirmExitFromRoom": "Do you want to exit the chat room?<br/>Exiting will delete your chat history and chat room information.",
|
||||||
|
"normalRoom": "Basic Room",
|
||||||
|
"timerRoom": "Timer Room",
|
||||||
|
"normalRoomDescription": "<strong>Up to {{maxCount}} peoples</strong><br/>can join.",
|
||||||
|
"timerRoomDescription": "<strong>When setting the timer,</strong><br/>the conversation is automatically deleted.",
|
||||||
|
"button": {
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"previous": "Previous",
|
||||||
|
"selectRoomUser": "Choice user",
|
||||||
|
"openRoom": "Open chat room"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
"common": {
|
"common": {
|
||||||
"messages": {
|
"messages": {
|
||||||
"no": "No",
|
"no": "No",
|
||||||
"yes": "Yes"
|
"yes": "Yes",
|
||||||
|
"confirm": "Confirm"
|
||||||
},
|
},
|
||||||
"units": {
|
"units": {
|
||||||
"date": "Date",
|
"date": "Date",
|
||||||
|
@ -17,6 +18,14 @@
|
||||||
"tomorrowAfternoon": "Tomorrow afternoon",
|
"tomorrowAfternoon": "Tomorrow afternoon",
|
||||||
"weekLaterWith": "(A) {{week}} week(s) later",
|
"weekLaterWith": "(A) {{week}} week(s) later",
|
||||||
"monthLaterWith": "(A) {{month}} month(s) later"
|
"monthLaterWith": "(A) {{month}} month(s) later"
|
||||||
|
},
|
||||||
|
"file": {
|
||||||
|
"errors": {
|
||||||
|
"failToUpload": "File upload failed.",
|
||||||
|
"notSupporedType": "File format is not supported. <br/> ({{supporedType}})",
|
||||||
|
"notAcceptableMime": "File type is invalid. <br/> ({{supporedType}})",
|
||||||
|
"oversize": "You cannot upload files larger than {{size}} megabytes."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,13 +6,10 @@
|
||||||
"openRoom": "대화방 열기",
|
"openRoom": "대화방 열기",
|
||||||
"turnOnRoomAlert": "대화방 알람 켜기",
|
"turnOnRoomAlert": "대화방 알람 켜기",
|
||||||
"turnOffRoomAlert": "대화방 알람 끄기",
|
"turnOffRoomAlert": "대화방 알람 끄기",
|
||||||
"exitFromRoom": "대화방 나가기",
|
"exitFromRoom": "대화방 나가기"
|
||||||
"dialog": {
|
|
||||||
"titleExitFromRoom": "대화방 나가기",
|
|
||||||
"confirmExitFromRoom": "대화방을 나가시겠습니까?<br/>나가기를 하면 대화내용 및 대화방 정보가 삭제됩니다."
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"label": {
|
"label": {
|
||||||
|
"chat": "대화",
|
||||||
"menu": "메뉴",
|
"menu": "메뉴",
|
||||||
"search": "검색",
|
"search": "검색",
|
||||||
"notificationIsOn": "알림 켜짐",
|
"notificationIsOn": "알림 켜짐",
|
||||||
|
@ -26,5 +23,51 @@
|
||||||
"emailSend": "대화내용 메일전송",
|
"emailSend": "대화내용 메일전송",
|
||||||
"translation": "대화내용 번역",
|
"translation": "대화내용 번역",
|
||||||
"gams": "+GAMS"
|
"gams": "+GAMS"
|
||||||
|
},
|
||||||
|
"event": {
|
||||||
|
"inviteToRoomWith": "{{owner}}님이 {{inviter}}님을 초대했습니다.",
|
||||||
|
"exitFromRoomWith": "{{exitor}}님이 퇴장하셨습니다.",
|
||||||
|
"ejectedFromRoomWith": "{{requester}}님이 {{ejected}}님을 퇴장 시키셨습니다.",
|
||||||
|
"renamedRoomWith": "{{requester}}님이 대화방명을 '{{roomName}}'으로 변경하셨습니다.",
|
||||||
|
"setTimerWith": "{{requester}}님이 타이머를 설정하였습니다. ({{timer}})",
|
||||||
|
"iosCapture": "{{requester}}님이 대화내용을 캡쳐하였습니다.",
|
||||||
|
"showMassTranslationOfOriginal": "원본 보기",
|
||||||
|
"showMassTranslationOfTranslated": "번역 보기",
|
||||||
|
"showMassDetail": "전체 보기",
|
||||||
|
"readToHere": "여기까지 읽었습니다.",
|
||||||
|
"recalled": "회수된 메시지",
|
||||||
|
"scheduleTypeNew": "[이벤트] 등록",
|
||||||
|
"scheduleTypeUpdate": "[이벤트] 수정",
|
||||||
|
"scheduleTypeDelete": "[이벤트] 삭제",
|
||||||
|
"scheduleTypeDefault": "[이벤트] 조회중..",
|
||||||
|
"scheduleTypePrefix": "[이벤트] ",
|
||||||
|
"scheduleTypeSurfixLeft": " 전 알림",
|
||||||
|
"showPreviousEvents": "이전 대화 보기",
|
||||||
|
"moreUnreadEventsWith": "안읽은 메시지가 <span class=\"text-warn-color\">({{countOfUnread}})</span>개 더 있습니다."
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"label": "대화 에러",
|
||||||
|
"inputChatMessage": "대화 내용을 입력해 주세요.",
|
||||||
|
"maxLengthOfMassText": "스티커를 포함할 경우 {{maxLength}}자 이상 보낼 수 없습니다.",
|
||||||
|
"maxCountOfRoomMemberWith": "{{maxCount}}명 이상 대화할 수 없습니다.",
|
||||||
|
"emptyOpenRoomType": "대화방 타입을 선택해 주세요.",
|
||||||
|
"translateServerError": "번역하지 못했습니다."
|
||||||
|
},
|
||||||
|
"dialog": {
|
||||||
|
"title": {
|
||||||
|
"exitFromRoom": "대화방 나가기",
|
||||||
|
"newChatRoom": "새로운 대화방 추가"
|
||||||
|
},
|
||||||
|
"confirmExitFromRoom": "대화방을 나가시겠습니까?<br/>나가기를 하면 대화내용 및 대화방 정보가 삭제됩니다.",
|
||||||
|
"normalRoom": "일반 대화방",
|
||||||
|
"timerRoom": "타이머 대화방",
|
||||||
|
"normalRoomDescription": "<strong>{{maxCount}}명 까지</strong><br/>참여가 가능합니다.",
|
||||||
|
"timerRoomDescription": "<strong>타이머 설정시</strong><br/>대화내용이 자동으로 삭제됩니다.",
|
||||||
|
"button": {
|
||||||
|
"cancel": "취소",
|
||||||
|
"previous": "이전",
|
||||||
|
"selectRoomUser": "대화방 멤버 선택",
|
||||||
|
"openRoom": "대화방 생성"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
"common": {
|
"common": {
|
||||||
"messages": {
|
"messages": {
|
||||||
"no": "아니요",
|
"no": "아니요",
|
||||||
"yes": "예"
|
"yes": "예",
|
||||||
|
"confirm": "확인"
|
||||||
},
|
},
|
||||||
"units": {
|
"units": {
|
||||||
"date": "날짜",
|
"date": "날짜",
|
||||||
|
@ -17,6 +18,14 @@
|
||||||
"tomorrowAfternoon": "내일 오후",
|
"tomorrowAfternoon": "내일 오후",
|
||||||
"weekLaterWith": "{{week}}주일 뒤",
|
"weekLaterWith": "{{week}}주일 뒤",
|
||||||
"monthLaterWith": "{{month}}달 뒤"
|
"monthLaterWith": "{{month}}달 뒤"
|
||||||
|
},
|
||||||
|
"file": {
|
||||||
|
"errors": {
|
||||||
|
"failToUpload": "파일 업로드에 실패하였습니다.",
|
||||||
|
"notSupporedType": "지원하지 않는 파일형식입니다. <br/> ({{supporedType}})",
|
||||||
|
"notAcceptableMime": "유효하지 않은 파일 타입입니다. <br/> ({{supporedType}})",
|
||||||
|
"oversize": "{{maxSize}}MB 이상 파일을 업로드 할 수 없습니다."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
// Material theming tools
|
// Material theming tools
|
||||||
@import '~@angular/material/theming';
|
@import 'mixins';
|
||||||
|
|
||||||
// Include core Angular Material styles
|
// Include core Angular Material styles
|
||||||
@include mat-core();
|
@include mat-core();
|
||||||
|
|
||||||
//creative
|
//creative
|
||||||
@import 'global/default';
|
@import 'global/default';
|
||||||
|
@import 'global/ucap-ui';
|
||||||
@import 'global/material-ui';
|
@import 'global/material-ui';
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
// Material theming tools
|
// Material theming tools
|
||||||
@import '~@angular/material/theming';
|
@import '~@angular/material/theming';
|
||||||
|
|
||||||
@import '~@ucap/ng-ui-material/material';
|
|
||||||
|
|
||||||
@import 'setting/variables';
|
@import 'setting/variables';
|
||||||
|
|
||||||
|
@import '~@ucap/ng-ui-material/material';
|
||||||
|
|
||||||
@import 'mixins/font';
|
@import 'mixins/font';
|
||||||
@import 'mixins/dom';
|
@import 'mixins/dom';
|
||||||
|
|
||||||
|
|
|
@ -139,7 +139,7 @@
|
||||||
.mat-tab-label[aria-selected='true'] {
|
.mat-tab-label[aria-selected='true'] {
|
||||||
.mat-tab-label-content {
|
.mat-tab-label-content {
|
||||||
.icon-item {
|
.icon-item {
|
||||||
background: mat-color($accent, 300);
|
background: mat-color($accent, 700);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -212,6 +212,7 @@
|
||||||
.mat-form-field-infix {
|
.mat-form-field-infix {
|
||||||
align-self: center;
|
align-self: center;
|
||||||
width: inherit;
|
width: inherit;
|
||||||
|
padding: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -499,10 +500,58 @@
|
||||||
.color-white {
|
.color-white {
|
||||||
color: $white;
|
color: $white;
|
||||||
}
|
}
|
||||||
|
//mat chip
|
||||||
|
.mat-chip {
|
||||||
|
&.mat-standard-chip {
|
||||||
|
background-color: mat-color($accent, A400);
|
||||||
|
color: mat-color($primary, default-contrast);
|
||||||
|
.mat-chip-remove {
|
||||||
|
//color: rgba(0, 0, 0, 0.87);
|
||||||
|
color: mat-color($primary, default-contrast);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.mat-chip.mat-standard-chip.mat-chip-selected.mat-primary {
|
||||||
|
background-color: mat-color($accent, 700);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
//mat checkbox
|
||||||
|
.mat-checkbox-inner-container {
|
||||||
|
width: 18px !important;
|
||||||
|
height: 18px !important;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
.mat-checkbox-checked {
|
||||||
|
&.mat-accent {
|
||||||
|
.mat-checkbox-background {
|
||||||
|
border: 2px solid mat-color($accent, 700);
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 2px;
|
||||||
|
.mat-checkbox-checkmark-path {
|
||||||
|
stroke: mat-color($accent, 700) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//mat dadge
|
//mat dadge
|
||||||
.mat-badge-accent .mat-badge-content,
|
.mat-badge-accent .mat-badge-content,
|
||||||
.weblink .mat-badge-content {
|
.weblink .mat-badge-content {
|
||||||
background-color: mat-color($warn, 400);
|
background-color: mat-color($warn, 500);
|
||||||
|
border: 1px solid mat-color($warn, 500);
|
||||||
|
}
|
||||||
|
.noti-sum {
|
||||||
|
.mat-badge-content {
|
||||||
|
right: 16px !important;
|
||||||
|
bottom: 12px !important;
|
||||||
|
min-width: 22px;
|
||||||
|
width: auto;
|
||||||
|
line-height: 20px;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 5px;
|
||||||
|
border-radius: 11px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//mat-card
|
//mat-card
|
||||||
.allim-card {
|
.allim-card {
|
||||||
|
@ -616,6 +665,43 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//mat slide toggle
|
||||||
|
.mat-slide-toggle {
|
||||||
|
.mat-slide-toggle-bar {
|
||||||
|
width: 32px;
|
||||||
|
height: 18px;
|
||||||
|
border-radius: 9px;
|
||||||
|
border: 1px solid #707070;
|
||||||
|
background-color: #fff;
|
||||||
|
.mat-slide-toggle-thumb-container {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
top: 2px;
|
||||||
|
left: 2px;
|
||||||
|
.mat-slide-toggle-thumb {
|
||||||
|
height: 12px;
|
||||||
|
width: 12px;
|
||||||
|
box-shadow: 0px 2px 1px -1px rgba(0, 0, 0, 0.2),
|
||||||
|
0px 1px 1px 0px rgba(0, 0, 0, 0.14),
|
||||||
|
0px 1px 3px 0px rgba(0, 0, 0, 0.12);
|
||||||
|
background-color: #999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.mat-checked {
|
||||||
|
.mat-slide-toggle-bar {
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid #fd578a;
|
||||||
|
.mat-slide-toggle-thumb-container {
|
||||||
|
transform: translate3d(14px, 0, 0);
|
||||||
|
.mat-slide-toggle-thumb {
|
||||||
|
background-color: #e42f66;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Btn Float
|
// Btn Float
|
||||||
.btn-main-float {
|
.btn-main-float {
|
||||||
right: 22px !important;
|
right: 22px !important;
|
||||||
|
|
6
src/assets/scss/global/_ucap-ui.scss
Normal file
6
src/assets/scss/global/_ucap-ui.scss
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
@import 'ucap/organization';
|
||||||
|
@import 'ucap/authentication';
|
||||||
|
@import 'ucap/group';
|
||||||
|
@import 'ucap/call';
|
||||||
|
@import 'ucap/message';
|
||||||
|
@import 'ucap/call';
|
205
src/assets/scss/global/ucap/_authentication.scss
Normal file
205
src/assets/scss/global/ucap/_authentication.scss
Normal file
|
@ -0,0 +1,205 @@
|
||||||
|
.ucap-authentication-login-container {
|
||||||
|
background-color: transparent !important;
|
||||||
|
@include screen(mid) {
|
||||||
|
width: 350px !important;
|
||||||
|
}
|
||||||
|
@include screen(xs) {
|
||||||
|
width: 300px !important;
|
||||||
|
}
|
||||||
|
.ucap-authentication-login-input-field {
|
||||||
|
border: 1px solid #cccccc;
|
||||||
|
border-radius: 2px;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 420px;
|
||||||
|
min-width: 150px;
|
||||||
|
height: 60px;
|
||||||
|
padding: 0 !important;
|
||||||
|
background-color: $white !important;
|
||||||
|
margin-top: 10px !important;
|
||||||
|
display: flex !important;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
overflow: hidden;
|
||||||
|
.ucap-authentication-login-input-icon {
|
||||||
|
align-self: center;
|
||||||
|
flex-basis: 45px;
|
||||||
|
margin-right: 16px !important;
|
||||||
|
margin-left: 16px;
|
||||||
|
height: 24px !important;
|
||||||
|
width: 24px !important;
|
||||||
|
@include screen(mid) {
|
||||||
|
height: 20px !important;
|
||||||
|
width: 20px !important;
|
||||||
|
margin-right: 10px !important;
|
||||||
|
}
|
||||||
|
@include screen(xs) {
|
||||||
|
height: 20px !important;
|
||||||
|
width: 20px !important;
|
||||||
|
margin-right: 10px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.mat-form-field {
|
||||||
|
.mat-form-field-wrapper {
|
||||||
|
.mat-form-field-underline {
|
||||||
|
height: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.mat-form-field-appearance-legacy {
|
||||||
|
.mat-form-field-ripple {
|
||||||
|
height: 0 !important;
|
||||||
|
}
|
||||||
|
&.mat-form-field-can-float {
|
||||||
|
.mat-form-field-autofill-control {
|
||||||
|
&:-webkit-autofill + .mat-form-field-label-wrapper {
|
||||||
|
.mat-form-field-label {
|
||||||
|
width: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:nth-child(1) {
|
||||||
|
margin-top: 30px !important;
|
||||||
|
width: 420px;
|
||||||
|
.mat-form-field {
|
||||||
|
@include ucapMatSelect(60px, 0 16px);
|
||||||
|
}
|
||||||
|
@include screen(mid) {
|
||||||
|
margin-top: 23px !important;
|
||||||
|
width: 350px;
|
||||||
|
.mat-form-field {
|
||||||
|
@include ucapMatSelect(50px, 0 16px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@include screen(xs) {
|
||||||
|
margin-top: 23px !important;
|
||||||
|
width: 300px;
|
||||||
|
.mat-form-field {
|
||||||
|
@include ucapMatSelect(42px, 0 16px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:nth-child(2) {
|
||||||
|
.mat-form-field {
|
||||||
|
@include ucapMatFormField(0, 0, auto, 360px, 360px, 60px, 60px, white);
|
||||||
|
}
|
||||||
|
@include screen(mid) {
|
||||||
|
.mat-form-field {
|
||||||
|
@include ucapMatFormField(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
auto,
|
||||||
|
300px,
|
||||||
|
300px,
|
||||||
|
50px,
|
||||||
|
50px,
|
||||||
|
white
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@include screen(xs) {
|
||||||
|
.mat-form-field {
|
||||||
|
@include ucapMatFormField(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
auto,
|
||||||
|
250px,
|
||||||
|
250px,
|
||||||
|
42px,
|
||||||
|
42px,
|
||||||
|
white
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:nth-child(3) {
|
||||||
|
.mat-form-field {
|
||||||
|
@include ucapMatFormField(0, 0, 360px, 360px, 360px, 60px, 60px, white);
|
||||||
|
}
|
||||||
|
@include screen(mid) {
|
||||||
|
.mat-form-field {
|
||||||
|
@include ucapMatFormField(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
auto,
|
||||||
|
300px,
|
||||||
|
300px,
|
||||||
|
50px,
|
||||||
|
50px,
|
||||||
|
white
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@include screen(xs) {
|
||||||
|
.mat-form-field {
|
||||||
|
@include ucapMatFormField(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
auto,
|
||||||
|
250px,
|
||||||
|
250px,
|
||||||
|
42px,
|
||||||
|
42px,
|
||||||
|
white
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@include screen(mid) {
|
||||||
|
width: 350px;
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
@include screen(xs) {
|
||||||
|
width: 300px;
|
||||||
|
height: 42px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ucap-authentication-login-error-container {
|
||||||
|
position: absolute;
|
||||||
|
width: 300px;
|
||||||
|
height: 80px;
|
||||||
|
//background-color: gold;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
bottom: 135px;
|
||||||
|
left: calc(50% - 150px);
|
||||||
|
font-size: 0.929em !important;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $lipstick !important;
|
||||||
|
.mat-error {
|
||||||
|
font-size: 0.929em !important;
|
||||||
|
line-height: 1.7 !important;
|
||||||
|
color: $lipstick !important;
|
||||||
|
@include screen(xs) {
|
||||||
|
font-size: 0.857em !important;
|
||||||
|
line-height: 1.5 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ucap-authentication-login-button-submit {
|
||||||
|
//transform: all 0.3s;
|
||||||
|
width: 100%;
|
||||||
|
height: 60px;
|
||||||
|
background-color: $black;
|
||||||
|
border-radius: 2px !important;
|
||||||
|
color: $white;
|
||||||
|
font-size: 1.429em !important;
|
||||||
|
@include font-family($font-semibold);
|
||||||
|
border: 0;
|
||||||
|
margin: 12px 0 0 !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
cursor: pointer;
|
||||||
|
@include screen(mid) {
|
||||||
|
margin-top: 8px !important;
|
||||||
|
font-size: 1.143em !important;
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
@include screen(xs) {
|
||||||
|
font-size: 1em !important;
|
||||||
|
height: 42px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
0
src/assets/scss/global/ucap/_call.scss
Normal file
0
src/assets/scss/global/ucap/_call.scss
Normal file
0
src/assets/scss/global/ucap/_chat.scss
Normal file
0
src/assets/scss/global/ucap/_chat.scss
Normal file
0
src/assets/scss/global/ucap/_group.scss
Normal file
0
src/assets/scss/global/ucap/_group.scss
Normal file
0
src/assets/scss/global/ucap/_message.scss
Normal file
0
src/assets/scss/global/ucap/_message.scss
Normal file
7
src/assets/scss/global/ucap/_organization.scss
Normal file
7
src/assets/scss/global/ucap/_organization.scss
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
.ucap-organization-profile-image-01-image-container {
|
||||||
|
border-radius: 50%;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
margin-left: 2px;
|
||||||
|
}
|
|
@ -1,15 +1,8 @@
|
||||||
:root {
|
:root {
|
||||||
--ucap-screen-max-xs: 575;
|
|
||||||
--ucap-screen-min-sm: 576;
|
|
||||||
--ucap-screen-max-sm: 767;
|
|
||||||
--ucap-screen-min-md: 768;
|
|
||||||
--ucap-screen-max-md: 991;
|
|
||||||
--ucap-screen-min-lg: 992;
|
|
||||||
--ucap-screen-max-lg: 1199;
|
|
||||||
--ucap-screen-min-xl: 1200;
|
|
||||||
|
|
||||||
--ucap-organization-search-for-tenant-border-width: 1px;
|
--ucap-organization-search-for-tenant-border-width: 1px;
|
||||||
--ucap-organization-search-for-tenant-border-color: #e42f66;
|
--ucap-organization-search-for-tenant-border-color: #e42f66;
|
||||||
|
|
||||||
|
--ucap-organization-profile-list-item-01-size: 70px;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fonts Family
|
// Fonts Family
|
||||||
|
@ -96,26 +89,22 @@ $bg-linear-gradient: linear-gradient(57deg, #ffe1ba 13%, #f5878c 87%);
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
$lg-red: (
|
// Theming color set/////////////////////////////
|
||||||
50: #ffffff,
|
$ucap-color-primary: (
|
||||||
100: #fff9fc,
|
50: #f0f0f0,
|
||||||
200: #f1e1e5,
|
100: #e2e2e2,
|
||||||
300: #ef4c73,
|
200: #d4d4d4,
|
||||||
400: #ffbf2a,
|
300: #cccccc,
|
||||||
//#ec407a
|
400: #aaa4a6,
|
||||||
500: #ed097e,
|
500: #81757a,
|
||||||
600: #d81b60,
|
600: #584f52,
|
||||||
700: #c2185b,
|
700: #474244,
|
||||||
800: #ad1457,
|
800: #3b3637,
|
||||||
900: #5f2a41,
|
900: #2d2a2c,
|
||||||
A100: #ff80ab,
|
A100: #f7f8fa,
|
||||||
A200: #ff4081,
|
A200: #f1f2f6,
|
||||||
A400: #ff3399,
|
A400: #999999,
|
||||||
A700: #c51162,
|
A700: #333333,
|
||||||
B100: #4f4f4f,
|
|
||||||
B200: #67545b,
|
|
||||||
G100: #ef4c73,
|
|
||||||
G900: #352a37,
|
|
||||||
contrast: (
|
contrast: (
|
||||||
50: $dark-primary-text,
|
50: $dark-primary-text,
|
||||||
100: $dark-primary-text,
|
100: $dark-primary-text,
|
||||||
|
@ -128,11 +117,84 @@ $lg-red: (
|
||||||
800: $light-primary-text,
|
800: $light-primary-text,
|
||||||
900: $light-primary-text,
|
900: $light-primary-text,
|
||||||
A100: $dark-primary-text,
|
A100: $dark-primary-text,
|
||||||
A200: $light-primary-text,
|
A200: $dark-primary-text,
|
||||||
A400: $light-primary-text,
|
A400: $light-primary-text,
|
||||||
A700: $light-primary-text,
|
A700: $light-primary-text
|
||||||
B100: $light-primary-text,
|
|
||||||
G100: $dark-primary-text,
|
|
||||||
G900: $light-primary-text
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$ucap-color-accent: (
|
||||||
|
50: #fef1f4,
|
||||||
|
100: #fce7ed,
|
||||||
|
200: #ffd9e5,
|
||||||
|
300: #ffb5cc,
|
||||||
|
400: #fd78a1,
|
||||||
|
500: #fd578a,
|
||||||
|
600: #f83772,
|
||||||
|
700: #e42f66,
|
||||||
|
800: #dc225b,
|
||||||
|
900: #c21e50,
|
||||||
|
A100: #fff2f3,
|
||||||
|
A200: #ffc5ca,
|
||||||
|
A400: #f67f8a,
|
||||||
|
A700: #ec5361,
|
||||||
|
contrast: (
|
||||||
|
50: $dark-primary-text,
|
||||||
|
100: $dark-primary-text,
|
||||||
|
200: $dark-primary-text,
|
||||||
|
300: $light-primary-text,
|
||||||
|
400: $light-primary-text,
|
||||||
|
500: $light-primary-text,
|
||||||
|
600: $light-primary-text,
|
||||||
|
700: $light-primary-text,
|
||||||
|
800: $light-primary-text,
|
||||||
|
900: $light-primary-text,
|
||||||
|
A100: $dark-primary-text,
|
||||||
|
A200: $dark-primary-text,
|
||||||
|
A400: $light-primary-text,
|
||||||
|
A700: $light-primary-text
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$ucap-color-warn: (
|
||||||
|
50: #fefaf6,
|
||||||
|
100: #fef6ec,
|
||||||
|
200: #ffe8cb,
|
||||||
|
300: #ffda9a,
|
||||||
|
400: #fbca69,
|
||||||
|
500: #fcb954,
|
||||||
|
600: #faa640,
|
||||||
|
700: #f69532,
|
||||||
|
800: #e68118,
|
||||||
|
900: #d8750f,
|
||||||
|
A100: #fff3ef,
|
||||||
|
A200: #ffeadf,
|
||||||
|
A400: #ffbf9e,
|
||||||
|
A700: #ff6c20,
|
||||||
|
contrast: (
|
||||||
|
50: $dark-primary-text,
|
||||||
|
100: $dark-primary-text,
|
||||||
|
200: $dark-primary-text,
|
||||||
|
300: $dark-primary-text,
|
||||||
|
400: $light-primary-text,
|
||||||
|
500: $light-primary-text,
|
||||||
|
600: $light-primary-text,
|
||||||
|
700: $light-primary-text,
|
||||||
|
800: $light-primary-text,
|
||||||
|
900: $light-primary-text,
|
||||||
|
A100: $dark-primary-text,
|
||||||
|
A200: $dark-primary-text,
|
||||||
|
A400: $light-primary-text,
|
||||||
|
A700: $light-primary-text
|
||||||
|
)
|
||||||
|
);
|
||||||
|
/////////////////////////////Theming color set //
|
||||||
|
|
||||||
|
$ucap-screen-max-xs: 575;
|
||||||
|
$ucap-screen-min-sm: 576;
|
||||||
|
$ucap-screen-max-sm: 767;
|
||||||
|
$ucap-screen-min-md: 768;
|
||||||
|
$ucap-screen-max-md: 991;
|
||||||
|
$ucap-screen-min-lg: 992;
|
||||||
|
$ucap-screen-max-lg: 1199;
|
||||||
|
$ucap-screen-min-xl: 1200;
|
||||||
|
|
|
@ -103,7 +103,7 @@ export const environment: Environment = {
|
||||||
commonApiModuleConfig: {
|
commonApiModuleConfig: {
|
||||||
hostConfig: {
|
hostConfig: {
|
||||||
protocol: 'http',
|
protocol: 'http',
|
||||||
domain: 'lftalk2.lfcorp.com',
|
domain: '13.124.88.127',
|
||||||
port: 8033
|
port: 8033
|
||||||
},
|
},
|
||||||
urls: commonApiUrls,
|
urls: commonApiUrls,
|
||||||
|
@ -115,8 +115,8 @@ export const environment: Environment = {
|
||||||
publicApiModuleConfig: {
|
publicApiModuleConfig: {
|
||||||
hostConfig: {
|
hostConfig: {
|
||||||
protocol: 'http',
|
protocol: 'http',
|
||||||
domain: 'lftalk2.lfcorp.com',
|
domain: '13.124.88.127',
|
||||||
port: 8033
|
port: 8011
|
||||||
},
|
},
|
||||||
urls: publicApiUrls
|
urls: publicApiUrls
|
||||||
},
|
},
|
||||||
|
@ -124,7 +124,7 @@ export const environment: Environment = {
|
||||||
externalApiModuleConfig: {
|
externalApiModuleConfig: {
|
||||||
hostConfig: {
|
hostConfig: {
|
||||||
protocol: 'http',
|
protocol: 'http',
|
||||||
domain: 'lftalk2.lfcorp.com',
|
domain: '13.124.88.127',
|
||||||
port: 8011
|
port: 8011
|
||||||
},
|
},
|
||||||
urls: externalApiUrls
|
urls: externalApiUrls
|
||||||
|
@ -133,7 +133,7 @@ export const environment: Environment = {
|
||||||
messageApiModuleConfig: {
|
messageApiModuleConfig: {
|
||||||
hostConfig: {
|
hostConfig: {
|
||||||
protocol: 'http',
|
protocol: 'http',
|
||||||
domain: 'lftalk2.lfcorp.com',
|
domain: '13.124.88.127',
|
||||||
port: 9097
|
port: 9097
|
||||||
},
|
},
|
||||||
urls: messageApiUrls
|
urls: messageApiUrls
|
||||||
|
@ -142,7 +142,7 @@ export const environment: Environment = {
|
||||||
promptApiModuleConfig: {
|
promptApiModuleConfig: {
|
||||||
hostConfig: {
|
hostConfig: {
|
||||||
protocol: 'http',
|
protocol: 'http',
|
||||||
domain: 'lftalk2.lfcorp.com',
|
domain: '13.124.88.127',
|
||||||
port: 9097
|
port: 9097
|
||||||
},
|
},
|
||||||
urls: promptUrls
|
urls: promptUrls
|
||||||
|
@ -151,7 +151,7 @@ export const environment: Environment = {
|
||||||
piModuleConfig: {
|
piModuleConfig: {
|
||||||
hostConfig: {
|
hostConfig: {
|
||||||
protocol: 'http',
|
protocol: 'http',
|
||||||
domain: 'lftalk2.lfcorp.com',
|
domain: '13.124.88.127',
|
||||||
port: 9097
|
port: 9097
|
||||||
},
|
},
|
||||||
urls: piUrls
|
urls: piUrls
|
||||||
|
@ -166,7 +166,7 @@ export const environment: Environment = {
|
||||||
protocolModuleConfig: {
|
protocolModuleConfig: {
|
||||||
hostConfig: {
|
hostConfig: {
|
||||||
protocol: 'ws',
|
protocol: 'ws',
|
||||||
domain: 'lftalk2.lfcorp.com',
|
domain: '13.124.88.127',
|
||||||
port: 8080
|
port: 8080
|
||||||
},
|
},
|
||||||
urls: protocolUrls,
|
urls: protocolUrls,
|
||||||
|
@ -181,6 +181,6 @@ export const environment: Environment = {
|
||||||
},
|
},
|
||||||
pingProtocolModuleConfig: {
|
pingProtocolModuleConfig: {
|
||||||
statusCode: 'O',
|
statusCode: 'O',
|
||||||
interval: 5
|
interval: 20
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -107,7 +107,7 @@ export const environment: Environment = {
|
||||||
hostConfig: {
|
hostConfig: {
|
||||||
protocol: 'http',
|
protocol: 'http',
|
||||||
domain: '13.124.88.127',
|
domain: '13.124.88.127',
|
||||||
port: 8033
|
port: 8011
|
||||||
},
|
},
|
||||||
urls: commonApiUrls,
|
urls: commonApiUrls,
|
||||||
acceptableFileExtensions: commonApiacceptableFileExtensions,
|
acceptableFileExtensions: commonApiacceptableFileExtensions,
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user