sync
This commit is contained in:
parent
98ff58c39e
commit
eded98a6cf
6
package-lock.json
generated
6
package-lock.json
generated
|
@ -2022,9 +2022,9 @@
|
|||
"integrity": "sha512-GA9MDcwCvtxI0gOysgRm7DDHIfKfhCkDSa69QBFIEgWbob2OdGYKvxfymr6lGdl+vY7AqjlJXvSFkA1b0rTy1A=="
|
||||
},
|
||||
"@ucap/ng-core": {
|
||||
"version": "0.0.7",
|
||||
"resolved": "https://nexus.loafle.net/repository/npm-all/@ucap/ng-core/-/ng-core-0.0.7.tgz",
|
||||
"integrity": "sha512-ZC6LE3A0bg+REGbzDI/i1ad7mGpKsw6X0UtZ+Q8TUthHNv0DfWEieHFCgfYTRY1u022XyQ4ViOsrq9KunU1vfw=="
|
||||
"version": "0.0.8",
|
||||
"resolved": "https://nexus.loafle.net/repository/npm-all/@ucap/ng-core/-/ng-core-0.0.8.tgz",
|
||||
"integrity": "sha512-VMvitw2PnaGo4tsdD9EJcvzVi5Kt+xjzA6z09uLavPpAWViFXTx7P76N1nt7XMgACRAMOTMyNocWTbFs6oKsqA=="
|
||||
},
|
||||
"@ucap/ng-i18n": {
|
||||
"version": "0.0.6",
|
||||
|
|
91
package.json
91
package.json
|
@ -31,24 +31,39 @@
|
|||
"@ngrx/entity": "^9.2.0",
|
||||
"@ngrx/router-store": "^9.2.0",
|
||||
"@ngrx/store": "^9.2.0",
|
||||
"@ucap/api": "~0.0.4",
|
||||
"@ucap/api-common": "~0.0.11",
|
||||
"@ucap/api-external": "~0.0.5",
|
||||
"@ucap/api-message": "~0.0.3",
|
||||
"@ucap/api-prompt": "~0.0.3",
|
||||
"@ucap/api-public": "~0.0.4",
|
||||
"@ucap/core": "~0.0.14",
|
||||
"@ucap/logger": "~0.0.13",
|
||||
"@ucap/native": "~0.0.19",
|
||||
"@ucap/api": "~0.0.5",
|
||||
"@ucap/api-common": "~0.0.12",
|
||||
"@ucap/api-contact": "~0.0.5",
|
||||
"@ucap/api-external": "~0.0.8",
|
||||
"@ucap/api-message": "~0.0.7",
|
||||
"@ucap/api-prompt": "~0.0.6",
|
||||
"@ucap/api-public": "~0.0.6",
|
||||
"@ucap/api-webex": "~0.0.2",
|
||||
"@ucap/core": "~0.0.15",
|
||||
"@ucap/domain-authentication": "~0.0.4",
|
||||
"@ucap/domain-authorization": "~0.0.3",
|
||||
"@ucap/domain-call": "~0.0.4",
|
||||
"@ucap/domain-chat": "~0.0.3",
|
||||
"@ucap/domain-common": "~0.0.1",
|
||||
"@ucap/domain-group": "~0.0.2",
|
||||
"@ucap/domain-message": "~0.0.1",
|
||||
"@ucap/domain-organization": "~0.0.1",
|
||||
"@ucap/domain-status": "~0.0.1",
|
||||
"@ucap/electron-native": "~0.0.19",
|
||||
"@ucap/i18n": "~0.0.2",
|
||||
"@ucap/logger": "~0.0.14",
|
||||
"@ucap/native": "~0.0.27",
|
||||
"@ucap/ng-api-common": "~0.0.1",
|
||||
"@ucap/ng-api-external": "~0.0.1",
|
||||
"@ucap/ng-api-message": "~0.0.1",
|
||||
"@ucap/ng-api-prompt": "~0.0.1",
|
||||
"@ucap/ng-api-public": "~0.0.1",
|
||||
"@ucap/ng-core": "~0.0.7",
|
||||
"@ucap/ng-api-webex": "~0.0.1",
|
||||
"@ucap/ng-api-contact": "~0.0.2",
|
||||
"@ucap/ng-core": "~0.0.9",
|
||||
"@ucap/ng-logger": "~0.0.2",
|
||||
"@ucap/ng-i18n": "~0.0.6",
|
||||
"@ucap/ng-native": "~0.0.5",
|
||||
"@ucap/ng-i18n": "~0.0.8",
|
||||
"@ucap/ng-native": "~0.0.12",
|
||||
"@ucap/ng-pi": "~0.0.1",
|
||||
"@ucap/ng-protocol": "~0.0.3",
|
||||
"@ucap/ng-protocol-authentication": "~0.0.3",
|
||||
|
@ -66,35 +81,37 @@
|
|||
"@ucap/ng-protocol-status": "~0.0.3",
|
||||
"@ucap/ng-protocol-sync": "~0.0.3",
|
||||
"@ucap/ng-protocol-umg": "~0.0.3",
|
||||
"@ucap/ng-store-authentication": "~0.0.14",
|
||||
"@ucap/ng-store-chat": "~0.0.66",
|
||||
"@ucap/ng-store-group": "~0.0.22",
|
||||
"@ucap/ng-store-organization": "~0.0.20",
|
||||
"@ucap/ng-store-authentication": "~0.0.17",
|
||||
"@ucap/ng-store-chat": "~0.0.74",
|
||||
"@ucap/ng-store-group": "~0.0.25",
|
||||
"@ucap/ng-store-organization": "~0.0.23",
|
||||
"@ucap/ng-store-call": "~0.0.7",
|
||||
"@ucap/ng-web-socket": "~0.0.2",
|
||||
"@ucap/ng-web-storage": "~0.0.3",
|
||||
"@ucap/ng-ui": "0.0.97",
|
||||
"@ucap/ng-ui-organization": "~0.0.202",
|
||||
"@ucap/ng-ui-authentication": "~0.0.29",
|
||||
"@ucap/ng-ui-group": "~0.0.78",
|
||||
"@ucap/ng-ui-chat": "~0.0.72",
|
||||
"@ucap/ng-ui": "~0.0.108",
|
||||
"@ucap/ng-ui-organization": "~0.0.222",
|
||||
"@ucap/ng-ui-authentication": "~0.0.32",
|
||||
"@ucap/ng-ui-group": "~0.0.87",
|
||||
"@ucap/ng-ui-chat": "~0.0.80",
|
||||
"@ucap/ng-ui-call": "~0.0.15",
|
||||
"@ucap/ng-ui-material": "~0.0.4",
|
||||
"@ucap/ng-ui-skin-default": "~0.0.1",
|
||||
"@ucap/pi": "~0.0.8",
|
||||
"@ucap/protocol": "~0.0.17",
|
||||
"@ucap/protocol-authentication": "~0.0.5",
|
||||
"@ucap/protocol-buddy": "~0.0.5",
|
||||
"@ucap/protocol-event": "~0.0.6",
|
||||
"@ucap/protocol-file": "~0.0.6",
|
||||
"@ucap/protocol-group": "~0.0.5",
|
||||
"@ucap/protocol-info": "~0.0.9",
|
||||
"@ucap/protocol-inner": "~0.0.4",
|
||||
"@ucap/protocol-option": "~0.0.7",
|
||||
"@ucap/protocol-ping": "~0.0.6",
|
||||
"@ucap/protocol-query": "~0.0.5",
|
||||
"@ucap/protocol-room": "~0.0.7",
|
||||
"@ucap/protocol-service": "~0.0.4",
|
||||
"@ucap/protocol-status": "~0.0.5",
|
||||
"@ucap/protocol-sync": "~0.0.6",
|
||||
"@ucap/pi": "~0.0.9",
|
||||
"@ucap/protocol": "~0.0.20",
|
||||
"@ucap/protocol-authentication": "~0.0.7",
|
||||
"@ucap/protocol-buddy": "~0.0.6",
|
||||
"@ucap/protocol-event": "~0.0.11",
|
||||
"@ucap/protocol-file": "~0.0.7",
|
||||
"@ucap/protocol-group": "~0.0.6",
|
||||
"@ucap/protocol-info": "~0.0.10",
|
||||
"@ucap/protocol-inner": "~0.0.5",
|
||||
"@ucap/protocol-option": "~0.0.9",
|
||||
"@ucap/protocol-ping": "~0.0.7",
|
||||
"@ucap/protocol-query": "~0.0.8",
|
||||
"@ucap/protocol-room": "~0.0.9",
|
||||
"@ucap/protocol-service": "~0.0.5",
|
||||
"@ucap/protocol-status": "~0.0.6",
|
||||
"@ucap/protocol-sync": "~0.0.8",
|
||||
"@ucap/protocol-umg": "~0.0.5",
|
||||
"@ucap/ui-scss": "~0.0.5",
|
||||
"@ucap/web-socket": "~0.0.10",
|
||||
|
|
|
@ -15,10 +15,13 @@ import { AppAuthenticationService } from './services/app-authentication.service'
|
|||
import { AppNotificationService } from './services/app-notification.service';
|
||||
import { AppNativeService } from './services/app-native.service';
|
||||
import { AppService } from './services/app.service';
|
||||
import { AppCallService } from './services/app-call.service';
|
||||
import { AppChatService } from './services/app-chat.service';
|
||||
import { AppFileService } from './services/app-file.service';
|
||||
import { AppGroupService } from './services/app-group.service';
|
||||
import { AppAccountService } from './services/app-account.service';
|
||||
import { AppUiService } from './services/app-ui.service';
|
||||
import { AppOrganizationService } from './services/app-organization.service';
|
||||
|
||||
const GUARDS = [AppAuthenticationGuard];
|
||||
const RESOLVERS = [AppSessionResolver];
|
||||
|
@ -27,10 +30,13 @@ const SERVICES = [
|
|||
AppAuthenticationService,
|
||||
AppNativeService,
|
||||
AppFileService,
|
||||
AppCallService,
|
||||
AppChatService,
|
||||
AppNotificationService,
|
||||
AppOrganizationService,
|
||||
AppGroupService,
|
||||
AppAccountService
|
||||
AppAccountService,
|
||||
AppUiService
|
||||
];
|
||||
|
||||
const axiosFactory = () => {
|
||||
|
|
|
@ -6,11 +6,12 @@ import { NoNaviLayoutComponent } from '@app/layouts/components/no-navi.layout.co
|
|||
|
||||
import { AppAuthenticationGuard } from '@app/guards/app-authentication.guard';
|
||||
import { AppSessionResolver } from './resolvers/app-session.resolver';
|
||||
import { NavigationType } from './types';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
redirectTo: '/group/(content:index)',
|
||||
redirectTo: `/${NavigationType.Group}/(content:index)`,
|
||||
pathMatch: 'full'
|
||||
},
|
||||
{
|
||||
|
@ -38,35 +39,35 @@ const routes: Routes = [
|
|||
},
|
||||
children: [
|
||||
{
|
||||
path: 'organization',
|
||||
path: NavigationType.Organization,
|
||||
loadChildren: () =>
|
||||
import('./pages/organization/organization.page.module').then(
|
||||
(m) => m.AppOrganizationPageModule
|
||||
)
|
||||
},
|
||||
{
|
||||
path: 'group',
|
||||
path: NavigationType.Group,
|
||||
loadChildren: () =>
|
||||
import('./pages/group/group.page.module').then(
|
||||
(m) => m.AppGroupPageModule
|
||||
)
|
||||
},
|
||||
{
|
||||
path: 'chat',
|
||||
path: NavigationType.Chat,
|
||||
loadChildren: () =>
|
||||
import('./pages/chat/chat.page.module').then(
|
||||
(m) => m.AppChatPageModule
|
||||
)
|
||||
},
|
||||
{
|
||||
path: 'call',
|
||||
path: NavigationType.Call,
|
||||
loadChildren: () =>
|
||||
import('./pages/call/call.page.module').then(
|
||||
(m) => m.AppCallPageModule
|
||||
)
|
||||
},
|
||||
{
|
||||
path: 'message',
|
||||
path: NavigationType.Message,
|
||||
loadChildren: () =>
|
||||
import('./pages/message/message.page.module').then(
|
||||
(m) => m.AppMessagePageModule
|
||||
|
|
|
@ -1,30 +1,44 @@
|
|||
import { fromEvent, interval, Subject } from 'rxjs';
|
||||
import { debounce, takeUntil } from 'rxjs/operators';
|
||||
|
||||
import {
|
||||
Component,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
AfterViewInit,
|
||||
Renderer2
|
||||
Renderer2,
|
||||
Inject
|
||||
} from '@angular/core';
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
import { Store } from '@ngrx/store';
|
||||
|
||||
import { NativeService } from '@ucap/native';
|
||||
|
||||
import { UCAP_NATIVE_SERVICE } from '@ucap/ng-native';
|
||||
|
||||
import { AppActions } from '@app/store/actions';
|
||||
import { fromEvent, interval, Subject } from 'rxjs';
|
||||
import { debounce, takeUntil } from 'rxjs/operators';
|
||||
|
||||
import { AppAuthenticationService } from './services/app-authentication.service';
|
||||
import { AnimationBuilder, style, animate } from '@angular/animations';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.scss']
|
||||
})
|
||||
export class AppComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||
export class AppComponent implements OnInit, OnDestroy {
|
||||
private ngOnDestroySubject: Subject<void> = new Subject();
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private renderer2: Renderer2,
|
||||
private store: Store<any>,
|
||||
private appAuthenticationService: AppAuthenticationService
|
||||
private appAuthenticationService: AppAuthenticationService,
|
||||
@Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService,
|
||||
@Inject(DOCUMENT) private _document: any,
|
||||
private _animationBuilder: AnimationBuilder
|
||||
) {
|
||||
fromEvent(window, 'resize')
|
||||
.pipe(
|
||||
|
@ -38,6 +52,12 @@ export class AppComponent implements OnInit, OnDestroy, AfterViewInit {
|
|||
});
|
||||
});
|
||||
|
||||
fromEvent(window, 'unload')
|
||||
.pipe(takeUntil(this.ngOnDestroySubject))
|
||||
.subscribe((event: any) => {
|
||||
this.nativeService.app_postDestroy();
|
||||
});
|
||||
|
||||
// fromEvent(window, 'beforeunload')
|
||||
// .pipe(takeUntil(this.ngOnDestroySubject))
|
||||
// .subscribe((event: any) => {
|
||||
|
@ -50,6 +70,53 @@ export class AppComponent implements OnInit, OnDestroy, AfterViewInit {
|
|||
width: window.innerWidth,
|
||||
height: window.innerHeight
|
||||
});
|
||||
this.nativeService.app_postInit().then((info) => {
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
if (!!info.initUrl) {
|
||||
this.router.navigateByUrl(info.initUrl);
|
||||
}
|
||||
});
|
||||
|
||||
const splash = this._document.body.querySelector('#ucap-lg-web-splash');
|
||||
const player = this._animationBuilder
|
||||
.build([
|
||||
style({ opacity: '1' }),
|
||||
animate(
|
||||
'400ms ease',
|
||||
style({
|
||||
opacity: '0',
|
||||
zIndex: '-10'
|
||||
})
|
||||
)
|
||||
])
|
||||
.create(splash);
|
||||
|
||||
setTimeout(() => {
|
||||
player.play();
|
||||
}, 0);
|
||||
|
||||
// const preloader = this.renderer2.selectRootElement(
|
||||
// '#ucap-lg-web-preloader'
|
||||
// );
|
||||
// const fadeEffect = setInterval(() => {
|
||||
// if (!preloader.style.opacity) {
|
||||
// this.renderer2.setStyle(preloader, 'opacity', 1);
|
||||
// }
|
||||
// if (preloader.style.opacity > 0) {
|
||||
// this.renderer2.setStyle(
|
||||
// preloader,
|
||||
// 'opacity',
|
||||
// preloader.style.opacity - 0.1
|
||||
// );
|
||||
// } else {
|
||||
// this.renderer2.setStyle(preloader, 'display', 'none');
|
||||
// clearInterval(fadeEffect);
|
||||
// }
|
||||
// }, 200);
|
||||
|
||||
// this.renderer2.setStyle(preloader, 'display', 'none');
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
|
@ -59,13 +126,6 @@ export class AppComponent implements OnInit, OnDestroy, AfterViewInit {
|
|||
}
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
const preloader = this.renderer2.selectRootElement(
|
||||
'#ucap-lg-web-preloader'
|
||||
);
|
||||
this.renderer2.setStyle(preloader, 'display', 'none');
|
||||
}
|
||||
|
||||
private dispatchWindowSize(size: { width: number; height: number }) {
|
||||
this.store.dispatch(AppActions.windowResized(size));
|
||||
}
|
||||
|
|
|
@ -15,8 +15,10 @@ import { LoggerModule } from '@ucap/ng-logger';
|
|||
import { CommonApiModule } from '@ucap/ng-api-common';
|
||||
import { PublicApiModule } from '@ucap/ng-api-public';
|
||||
import { ExternalApiModule } from '@ucap/ng-api-external';
|
||||
import { ContactApiModule } from '@ucap/ng-api-contact';
|
||||
import { MessageApiModule } from '@ucap/ng-api-message';
|
||||
import { PromptApiModule } from '@ucap/ng-api-prompt';
|
||||
import { WebexApiModule } from '@ucap/ng-api-webex';
|
||||
|
||||
import { PiModule } from '@ucap/ng-pi';
|
||||
|
||||
|
@ -46,6 +48,7 @@ import { OrganizationStoreModule } from '@ucap/ng-store-organization';
|
|||
import { AuthenticationStoreModule } from '@ucap/ng-store-authentication';
|
||||
import { GroupStoreModule } from '@ucap/ng-store-group';
|
||||
import { ChatStoreModule } from '@ucap/ng-store-chat';
|
||||
import { CallStoreModule } from '@ucap/ng-store-call';
|
||||
|
||||
import { OrganizationUiModule } from '@ucap/ng-ui-organization';
|
||||
|
||||
|
@ -62,6 +65,7 @@ import { metaReducers } from '@app/store/state';
|
|||
import { AppAccountDialogModule } from '@app/dialogs/account/account.dialog.module';
|
||||
|
||||
import { environment } from '@environments';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
|
||||
@NgModule({
|
||||
declarations: [AppComponent],
|
||||
|
@ -121,13 +125,17 @@ import { environment } from '@environments';
|
|||
*/
|
||||
EffectsModule.forRoot([...effects]),
|
||||
|
||||
MatDialogModule,
|
||||
|
||||
LoggerModule.forRoot({}),
|
||||
|
||||
CommonApiModule.forRoot(environment.commonApiModuleConfig),
|
||||
PublicApiModule.forRoot(environment.publicApiModuleConfig),
|
||||
ExternalApiModule.forRoot(environment.externalApiModuleConfig),
|
||||
ContactApiModule.forRoot(environment.contactApiModuleConfig),
|
||||
MessageApiModule.forRoot(environment.messageApiModuleConfig),
|
||||
PromptApiModule.forRoot(environment.promptApiModuleConfig),
|
||||
WebexApiModule.forRoot(environment.webexApiModuleConfig),
|
||||
|
||||
PiModule.forRoot(environment.piModuleConfig),
|
||||
|
||||
|
@ -162,6 +170,10 @@ import { environment } from '@environments';
|
|||
eventRequestDefaultCount:
|
||||
environment.productConfig.chat.eventRequestDefaultCount
|
||||
}),
|
||||
CallStoreModule.forRoot({
|
||||
historyRequestDefaultCount:
|
||||
environment.productConfig.call.historyRequestDefaultCount
|
||||
}),
|
||||
|
||||
OrganizationUiModule.forRoot({}),
|
||||
|
||||
|
|
|
@ -13,11 +13,12 @@ import { MatSelectModule } from '@angular/material/select';
|
|||
import { MatTabsModule } from '@angular/material/tabs';
|
||||
|
||||
import { I18nModule } from '@ucap/ng-i18n';
|
||||
import { UiModule } from '@ucap/ng-ui';
|
||||
|
||||
import { UiscrollingModule } from '@ucap/ng-ui/scrolling';
|
||||
|
||||
import { AppLayoutsModule } from '@app/layouts/layouts.module';
|
||||
import { AppAccountSectionModule } from '@app/sections/account/account.section.module';
|
||||
|
||||
import { AppAuthenticationModule } from '@app/ucap/authentication/authentication.module';
|
||||
import { COMPONENTS } from './components';
|
||||
|
||||
@NgModule({
|
||||
|
@ -36,7 +37,9 @@ import { COMPONENTS } from './components';
|
|||
|
||||
I18nModule,
|
||||
|
||||
UiModule,
|
||||
UiscrollingModule,
|
||||
|
||||
AppAuthenticationModule,
|
||||
|
||||
AppLayoutsModule,
|
||||
AppAccountSectionModule
|
||||
|
|
|
@ -30,7 +30,10 @@
|
|||
<div class="settings-contents">
|
||||
<ul>
|
||||
<li>
|
||||
<mat-checkbox>
|
||||
<mat-checkbox
|
||||
[value]="settings.general.autoLaunch"
|
||||
(change)="onChangeForAutoStartOnBoot($event)"
|
||||
>
|
||||
{{
|
||||
'authentication:login.settings.autoStartOnBoot'
|
||||
| ucapI18n
|
||||
|
@ -38,12 +41,18 @@
|
|||
</mat-checkbox>
|
||||
</li>
|
||||
<li>
|
||||
<mat-checkbox>
|
||||
<mat-checkbox
|
||||
[value]="settings.general.autoLogin"
|
||||
(change)="onChangeForAutoLogin($event)"
|
||||
>
|
||||
{{ 'authentication:login.settings.autoLogin' | ucapI18n }}
|
||||
</mat-checkbox>
|
||||
</li>
|
||||
<li>
|
||||
<mat-checkbox>
|
||||
<mat-checkbox
|
||||
[value]="settings.general.startupHideWindow"
|
||||
(change)="onChangeForAutoHide($event)"
|
||||
>
|
||||
{{ 'authentication:login.settings.autoHide' | ucapI18n }}
|
||||
</mat-checkbox>
|
||||
</li>
|
||||
|
@ -66,7 +75,7 @@
|
|||
class="setting-select-obj ucap-mat-input-container"
|
||||
>
|
||||
<mat-select
|
||||
[value]="generalSetting.locale"
|
||||
[value]="settings.general.locale"
|
||||
(selectionChange)="onSelectionChangeLanguage($event)"
|
||||
>
|
||||
<mat-option
|
||||
|
@ -95,7 +104,7 @@
|
|||
class="setting-select-obj ucap-mat-input-container"
|
||||
>
|
||||
<mat-select
|
||||
[value]="generalSetting.hrInfoLocale"
|
||||
[value]="settings.general.hrInfoLocale"
|
||||
(selectionChange)="onSelectionChangeHrLanguage($event)"
|
||||
>
|
||||
<mat-option
|
||||
|
@ -122,10 +131,13 @@
|
|||
class="setting-select-obj ucap-mat-input-container"
|
||||
>
|
||||
<mat-select
|
||||
[class.ucap-select-placeholder-value]="
|
||||
!!timezonePlaceholder
|
||||
"
|
||||
#selectForTimezone
|
||||
[formControl]="formControlForTimezone"
|
||||
[placeholder]="timezonePlaceholder"
|
||||
[value]="generalSetting.timezone"
|
||||
[value]="settings.general.timezone"
|
||||
(openedChange)="onOpenedChangeTimezone($event)"
|
||||
>
|
||||
<ucap-virtual-scroll-viewport
|
||||
|
@ -162,6 +174,8 @@
|
|||
<mat-radio-group
|
||||
aria-label="Select an type of alarm"
|
||||
class="settings-radio-group"
|
||||
[value]="String(settings.notification.use)"
|
||||
(change)="onChangeForReceiveNotification($event)"
|
||||
>
|
||||
<mat-radio-button value="true">
|
||||
{{
|
||||
|
@ -186,20 +200,25 @@
|
|||
appearance="standard"
|
||||
class="setting-select-obj ucap-mat-input-container"
|
||||
>
|
||||
<mat-select>
|
||||
<mat-option value="sound">
|
||||
<mat-select
|
||||
[value]="settings.notification.method"
|
||||
(selectionChange)="
|
||||
onSelectionChangeMethodOfNotification($event)
|
||||
"
|
||||
>
|
||||
<mat-option [value]="NotificationMethod.Sound">
|
||||
{{
|
||||
'organization:settings.notification.methodTypeSound'
|
||||
| ucapI18n
|
||||
}}
|
||||
</mat-option>
|
||||
<mat-option value="alert">
|
||||
<mat-option [value]="NotificationMethod.Alert">
|
||||
{{
|
||||
'organization:settings.notification.methodTypeAlert'
|
||||
| ucapI18n
|
||||
}}
|
||||
</mat-option>
|
||||
<mat-option value="soundAndAlert">
|
||||
<mat-option [value]="NotificationMethod.SoundAndAlert">
|
||||
{{
|
||||
'organization:settings.notification.methodTypeSoundAndAlert'
|
||||
| ucapI18n
|
||||
|
@ -222,7 +241,12 @@
|
|||
appearance="standard"
|
||||
class="setting-select-obj ucap-mat-input-container"
|
||||
>
|
||||
<mat-select>
|
||||
<mat-select
|
||||
[value]="String(settings.notification.alertExposureTime)"
|
||||
(selectionChange)="
|
||||
onSelectionChangeAlertExposureTimeOfNotification($event)
|
||||
"
|
||||
>
|
||||
<mat-option value="5">
|
||||
5{{ 'common:units.second' | ucapI18n }}
|
||||
</mat-option>
|
||||
|
@ -249,7 +273,12 @@
|
|||
<div class="settings-contents">
|
||||
<ul>
|
||||
<li>
|
||||
<mat-checkbox>
|
||||
<mat-checkbox
|
||||
[value]="settings.notification.receiveForMessage"
|
||||
(change)="
|
||||
onChangeForReceiveForMessageOfNotification($event)
|
||||
"
|
||||
>
|
||||
{{
|
||||
'organization:settings.notification.receiveForMessageTypePopup'
|
||||
| ucapI18n
|
||||
|
@ -269,7 +298,7 @@
|
|||
<!-- 대화 -->
|
||||
<div class="messenger-settings-area">
|
||||
<div class="title-settings-subject">파일 전송</div>
|
||||
<div class="settings-contents02">
|
||||
<div class="settings-contents02" *ngIf="'electron' === platform">
|
||||
<div class="subtitle-settings-info">
|
||||
다운로드 폴더
|
||||
</div>
|
||||
|
@ -278,18 +307,12 @@
|
|||
color="accent"
|
||||
class="setting-input-obj input-set-obj ucap-mat-input-container"
|
||||
>
|
||||
<input
|
||||
matInput
|
||||
placeholder=""
|
||||
value=""
|
||||
[readonly]="'browser' === platform"
|
||||
/>
|
||||
<input matInput placeholder="" value="" />
|
||||
<button
|
||||
mat-button
|
||||
matSuffix
|
||||
mat-icon-button
|
||||
aria-label="file"
|
||||
[disabled]="'browser' === platform"
|
||||
>
|
||||
<mat-icon>folder</mat-icon>
|
||||
</button>
|
||||
|
@ -299,7 +322,6 @@
|
|||
mat-stroked-button
|
||||
color="primary"
|
||||
class="btn-folder-first"
|
||||
[disabled]="'browser' === platform"
|
||||
>
|
||||
폴더 초기화
|
||||
</button>
|
||||
|
@ -338,123 +360,7 @@
|
|||
</ng-template>
|
||||
<div class="secret-num-settings-area">
|
||||
<!-- 비밀번호 -->
|
||||
<div class="messenger-settings-area">
|
||||
<div class="title-settings-subject">
|
||||
{{ 'authentication:password.fields.changePassword' | ucapI18n }}
|
||||
</div>
|
||||
<div class="settings-contents02">
|
||||
<div class="subtitle-settings-info">
|
||||
{{
|
||||
'authentication:password.fields.currentPassword' | ucapI18n
|
||||
}}
|
||||
</div>
|
||||
<div class="settings-sub-content">
|
||||
<mat-form-field
|
||||
color="accent"
|
||||
class="setting-input-obj ucap-mat-input-container"
|
||||
>
|
||||
<input
|
||||
matInput
|
||||
placeholder="{{
|
||||
'authentication:password.placeholder.currentPassword'
|
||||
| ucapI18n
|
||||
}}"
|
||||
value=""
|
||||
/>
|
||||
<button
|
||||
mat-button
|
||||
matSuffix
|
||||
mat-icon-button
|
||||
aria-label="action"
|
||||
>
|
||||
<mat-icon>done</mat-icon>
|
||||
</button>
|
||||
<mat-hint>Hint</mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-contents02">
|
||||
<div class="subtitle-settings-info">
|
||||
{{ 'authentication:password.fields.newPassword' | ucapI18n }}
|
||||
</div>
|
||||
<div class="settings-sub-content">
|
||||
<mat-form-field
|
||||
color="accent"
|
||||
class="setting-input-obj ucap-mat-input-container"
|
||||
>
|
||||
<input
|
||||
matInput
|
||||
placeholder="{{
|
||||
'authentication:password.placeholder.newPassword'
|
||||
| ucapI18n
|
||||
}}"
|
||||
value=""
|
||||
/>
|
||||
<button
|
||||
mat-button
|
||||
matSuffix
|
||||
mat-icon-button
|
||||
aria-label="action"
|
||||
>
|
||||
<mat-icon>done</mat-icon>
|
||||
</button>
|
||||
<mat-hint
|
||||
>반드시 영어 소문자, 숫자, 특수문자 중 2가지 이상 사용해야
|
||||
합니다.</mat-hint
|
||||
>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field
|
||||
color="accent"
|
||||
class="setting-input-obj ucap-mat-input-container"
|
||||
>
|
||||
<input
|
||||
matInput
|
||||
placeholder="{{
|
||||
'authentication:password.placeholder.newPasswordConfirm'
|
||||
| ucapI18n
|
||||
}}"
|
||||
value=""
|
||||
/>
|
||||
<button
|
||||
mat-button
|
||||
matSuffix
|
||||
mat-icon-button
|
||||
aria-label="action"
|
||||
>
|
||||
<mat-icon>done</mat-icon>
|
||||
</button>
|
||||
<mat-error>Error</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pass-info-box">
|
||||
<dl>
|
||||
<dt>
|
||||
<mat-icon color="accent" class="bullet-ico-info"
|
||||
>info_outline</mat-icon
|
||||
>
|
||||
{{ 'authentication:password.notice.condition' | ucapI18n }}
|
||||
</dt>
|
||||
<dd>
|
||||
{{ 'authentication:password.notice.condition1' | ucapI18n }}
|
||||
</dd>
|
||||
<dd>
|
||||
{{ 'authentication:password.notice.condition2' | ucapI18n }}
|
||||
</dd>
|
||||
<dd>
|
||||
{{ 'authentication:password.notice.condition3' | ucapI18n }}
|
||||
</dd>
|
||||
<dd>
|
||||
{{ 'authentication:password.notice.condition4' | ucapI18n }}
|
||||
</dd>
|
||||
<dd>
|
||||
{{ 'authentication:password.notice.condition5' | ucapI18n }}
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
<app-authentication-change-password></app-authentication-change-password>
|
||||
</div>
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
||||
|
|
|
@ -12,10 +12,10 @@
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
padding: 10px 16px 9px;
|
||||
padding: 10px 16px;
|
||||
&:first-of-type {
|
||||
border-top: 0;
|
||||
padding: 20px 16px 9px;
|
||||
padding: 20px 16px 10px;
|
||||
}
|
||||
.title-settings-subject {
|
||||
color: #5c444b;
|
||||
|
@ -52,11 +52,11 @@
|
|||
.settings-contents {
|
||||
ul {
|
||||
li {
|
||||
padding: 6px 0 7px;
|
||||
padding: 6px 0;
|
||||
}
|
||||
}
|
||||
.settings-radio-group {
|
||||
padding: 6px 0 7px;
|
||||
padding: 6px 0;
|
||||
height: 42px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
|
|
@ -13,17 +13,27 @@ import {
|
|||
Inject,
|
||||
ViewChild
|
||||
} from '@angular/core';
|
||||
import { FormControl } from '@angular/forms';
|
||||
|
||||
import {
|
||||
MatDialogRef,
|
||||
MAT_DIALOG_DATA,
|
||||
MatDialog
|
||||
} from '@angular/material/dialog';
|
||||
import { MatOptionSelectionChange } from '@angular/material/core';
|
||||
import { MatSelectChange, MatSelect } from '@angular/material/select';
|
||||
import { MatCheckboxChange } from '@angular/material/checkbox';
|
||||
import { MatRadioChange } from '@angular/material/radio';
|
||||
|
||||
import { ObjectUtil } from '@ucap/core';
|
||||
import { NotificationMethod } from '@ucap/domain-common';
|
||||
import { NativeService, NativeType } from '@ucap/native';
|
||||
|
||||
import { UCAP_NATIVE_SERVICE } from '@ucap/ng-native';
|
||||
import { I18nService } from '@ucap/ng-i18n';
|
||||
import { DateService } from '@ucap/ng-ui/date';
|
||||
import { VirtualScrollViewportComponent } from '@ucap/ng-ui/scrolling';
|
||||
import { TranslateService } from '@ucap/ng-ui-organization';
|
||||
|
||||
import { environment } from '@environments';
|
||||
|
||||
|
@ -34,10 +44,6 @@ import {
|
|||
ChatSetting,
|
||||
PresenceSetting
|
||||
} from '@app/models/settings';
|
||||
import { I18nService } from '@ucap/ng-i18n';
|
||||
import { VirtualScrollViewportComponent } from '@ucap/ng-ui';
|
||||
import { FormControl } from '@angular/forms';
|
||||
import { MatOptionSelectionChange } from '@angular/material/core';
|
||||
|
||||
export interface TimezoneData {
|
||||
displayName: string;
|
||||
|
@ -47,7 +53,9 @@ export interface TimezoneData {
|
|||
export interface SettingsDialogData {
|
||||
settings: Settings;
|
||||
}
|
||||
export interface SettingsDialogResult {}
|
||||
export interface SettingsDialogResult {
|
||||
settings: Settings;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-sections-account-settings',
|
||||
|
@ -66,10 +74,7 @@ export class SettingsDialogComponent implements OnInit, OnDestroy {
|
|||
|
||||
platform: 'browser' | 'electron' = 'electron';
|
||||
|
||||
generalSetting: GeneralSetting;
|
||||
notificationSetting: NotificationSetting;
|
||||
chatSetting: ChatSetting;
|
||||
presenceSetting: PresenceSetting;
|
||||
settings: Settings;
|
||||
|
||||
timezoneList: TimezoneData[];
|
||||
timezonePlaceholder: string;
|
||||
|
@ -78,15 +83,24 @@ export class SettingsDialogComponent implements OnInit, OnDestroy {
|
|||
supportedHrLanguages =
|
||||
environment.productConfig.organization.supportedLanguages;
|
||||
|
||||
String = String;
|
||||
NotificationMethod = NotificationMethod;
|
||||
|
||||
private ngOnDestroySubject: Subject<void> = new Subject();
|
||||
|
||||
constructor(
|
||||
public dialogRef: MatDialogRef<SettingsDialogData, SettingsDialogResult>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: SettingsDialogData,
|
||||
@Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService,
|
||||
private dateService: DateService,
|
||||
private i18nService: I18nService,
|
||||
private translateService: TranslateService,
|
||||
private changeDetectorRef: ChangeDetectorRef,
|
||||
public matDialog: MatDialog
|
||||
) {
|
||||
this.nativeService.platform_nativeType().then((type) => {
|
||||
// this.platform = 'electron';
|
||||
// return;
|
||||
switch (type) {
|
||||
case NativeType.Browser:
|
||||
this.platform = 'browser';
|
||||
|
@ -99,14 +113,9 @@ export class SettingsDialogComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
});
|
||||
|
||||
this.generalSetting = data.settings.general;
|
||||
this.notificationSetting = data.settings.notification;
|
||||
this.chatSetting = data.settings.chat;
|
||||
this.presenceSetting = data.settings.presence;
|
||||
this.settings = ObjectUtil.deepClone(data.settings);
|
||||
}
|
||||
|
||||
private ngOnDestroySubject: Subject<void> = new Subject();
|
||||
|
||||
ngOnInit(): void {
|
||||
this.generateTimezoneData();
|
||||
|
||||
|
@ -124,9 +133,27 @@ export class SettingsDialogComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
}
|
||||
|
||||
onSelectionChangeLanguage(event: MatSelectChange) {}
|
||||
onChangeForAutoStartOnBoot(event: MatCheckboxChange) {
|
||||
this.settings.general.autoLaunch = event.checked;
|
||||
}
|
||||
|
||||
onSelectionChangeHrLanguage(event: MatSelectChange) {}
|
||||
onChangeForAutoLogin(event: MatCheckboxChange) {
|
||||
this.settings.general.autoLogin = event.checked;
|
||||
}
|
||||
|
||||
onChangeForAutoHide(event: MatCheckboxChange) {
|
||||
this.settings.general.startupHideWindow = event.checked;
|
||||
}
|
||||
|
||||
onSelectionChangeLanguage(event: MatSelectChange) {
|
||||
this.i18nService.changeLanguage(event.value);
|
||||
this.settings.general.locale = event.value;
|
||||
}
|
||||
|
||||
onSelectionChangeHrLanguage(event: MatSelectChange) {
|
||||
this.translateService.use(event.value);
|
||||
this.settings.general.hrInfoLocale = event.value;
|
||||
}
|
||||
|
||||
onOpenedChangeTimezone(opened: boolean) {
|
||||
if (opened) {
|
||||
|
@ -139,15 +166,41 @@ export class SettingsDialogComponent implements OnInit, OnDestroy {
|
|||
if (!event.isUserInput) {
|
||||
return;
|
||||
}
|
||||
this.dateService.use(event.source.value);
|
||||
this.settings.general.timezone = event.source.value;
|
||||
}
|
||||
|
||||
onChangeForReceiveNotification(event: MatRadioChange) {
|
||||
const use = 'true' === event.value;
|
||||
console.log('onChangeForReceiveNotification', use);
|
||||
}
|
||||
|
||||
onSelectionChangeMethodOfNotification(event: MatSelectChange) {
|
||||
console.log('onSelectionChangeMethodOfNotification', event.value);
|
||||
}
|
||||
|
||||
onSelectionChangeAlertExposureTimeOfNotification(event: MatSelectChange) {
|
||||
const v = Number(event.value);
|
||||
console.log('onSelectionChangeAlertExposureTimeOfNotification', v);
|
||||
}
|
||||
|
||||
onChangeForReceiveForMessageOfNotification(event: MatCheckboxChange) {
|
||||
console.log('onChangeForReceiveForMessageOfNotification', event.checked);
|
||||
}
|
||||
|
||||
onClosed(event: MouseEvent): void {
|
||||
this.dialogRef.close();
|
||||
this.dialogRef.close({ settings: this.data.settings });
|
||||
}
|
||||
|
||||
onCancel() {}
|
||||
onCancel() {
|
||||
this.dialogRef.close({ settings: this.data.settings });
|
||||
}
|
||||
|
||||
onConfirm() {}
|
||||
onConfirm() {
|
||||
this.dialogRef.close({
|
||||
settings: this.settings
|
||||
});
|
||||
}
|
||||
|
||||
private generateTimezoneData() {
|
||||
const timezoneData = this.i18nService.t('locale:timezone', {
|
||||
|
@ -159,11 +212,14 @@ export class SettingsDialogComponent implements OnInit, OnDestroy {
|
|||
const displayName = `(UTC${moment.tz(name).format('Z')}) ${
|
||||
timezoneData[name]
|
||||
}`;
|
||||
if (-1 < displayName.indexOf('undefined')) {
|
||||
console.log('timezone', name);
|
||||
}
|
||||
timezoneList.push({
|
||||
displayName,
|
||||
name
|
||||
});
|
||||
if (name === this.generalSetting.timezone) {
|
||||
if (name === this.settings.general.timezone) {
|
||||
this.timezonePlaceholder = displayName;
|
||||
}
|
||||
}
|
||||
|
@ -176,12 +232,12 @@ export class SettingsDialogComponent implements OnInit, OnDestroy {
|
|||
|
||||
private setTimezoneData() {
|
||||
const timezoneIndex = this.timezoneList.findIndex(
|
||||
(t) => t.name === this.generalSetting.timezone
|
||||
(t) => t.name === this.settings.general.timezone
|
||||
);
|
||||
|
||||
if (-1 !== timezoneIndex) {
|
||||
if (!!this.vsTimezone && !!this.selectForTimezone) {
|
||||
this.vsTimezone.scrollToIndex(timezoneIndex);
|
||||
this.vsTimezone.scrollToIndex(timezoneIndex, 'start');
|
||||
this.selectForTimezone.value = this.timezoneList[timezoneIndex].name;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<div class="layout-container" fxLayout="column">
|
||||
<div class="layout-header" fxFlex="50px" fxLayout="row">
|
||||
<div fxFlex="1 1 auto">
|
||||
<div fxFlex="1 1 auto" class="layout-header-container">
|
||||
<ng-content
|
||||
class="layout-header-content"
|
||||
select="[appLayoutsDefaultDialog='header']"
|
||||
|
|
|
@ -10,6 +10,11 @@
|
|||
font-size: 1.143em;
|
||||
border-bottom: 1px solid #666;
|
||||
margin: 0 16px;
|
||||
&-container {
|
||||
flex: 1 1 auto;
|
||||
box-sizing: border-box;
|
||||
width: calc(100% - 30px);
|
||||
}
|
||||
.layout-header-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<div class="layout-container" fxLayout="row">
|
||||
<div class="navitab-page" fxFlex="0 0 60px">
|
||||
<div
|
||||
class="layout-container"
|
||||
fxLayout="row"
|
||||
[ngClass]="'electron==' ? 'electron' : ''"
|
||||
>
|
||||
<div class="navitab-page">
|
||||
<div class="gnb">
|
||||
<mat-toolbar class="mat-gnb-toolbar"
|
||||
><img
|
||||
|
@ -16,7 +20,7 @@
|
|||
class="global-menu"
|
||||
(selectedTabChange)="onSelectedTabChange($event)"
|
||||
>
|
||||
<mat-tab aria-label="Group">
|
||||
<mat-tab [aria-label]="NavigationType.Group">
|
||||
<ng-template mat-tab-label>
|
||||
<div
|
||||
class="icon-item"
|
||||
|
@ -65,7 +69,7 @@
|
|||
</div>
|
||||
</ng-template>
|
||||
</mat-tab>
|
||||
<mat-tab aria-label="Chat">
|
||||
<mat-tab [aria-label]="NavigationType.Chat">
|
||||
<ng-template mat-tab-label>
|
||||
<div
|
||||
class="icon-item"
|
||||
|
@ -102,7 +106,7 @@
|
|||
</div>
|
||||
</ng-template>
|
||||
</mat-tab>
|
||||
<mat-tab aria-label="Organization">
|
||||
<mat-tab [aria-label]="NavigationType.Organization">
|
||||
<ng-template mat-tab-label>
|
||||
<div
|
||||
class="icon-item"
|
||||
|
@ -158,7 +162,7 @@
|
|||
</ng-template>
|
||||
</mat-tab>
|
||||
|
||||
<mat-tab aria-label="Message">
|
||||
<!-- <mat-tab [aria-label]="NavigationType.Message">
|
||||
<ng-template mat-tab-label>
|
||||
<div
|
||||
class="icon-item"
|
||||
|
@ -195,9 +199,9 @@
|
|||
</svg>
|
||||
</div>
|
||||
</ng-template>
|
||||
</mat-tab>
|
||||
</mat-tab> -->
|
||||
|
||||
<mat-tab aria-label="Call">
|
||||
<mat-tab [aria-label]="NavigationType.Call">
|
||||
<ng-template mat-tab-label>
|
||||
<div
|
||||
class="icon-item"
|
||||
|
@ -247,6 +251,7 @@
|
|||
mode="side"
|
||||
opened="true"
|
||||
[disableClose]="true"
|
||||
(openedChange)="onOpenStart($event)"
|
||||
>
|
||||
<ucap-float-action-button
|
||||
*ngIf="fabButtonShow"
|
||||
|
@ -254,7 +259,10 @@
|
|||
[useCustomDefaultIcon]="fabUseCustomDefaultIcon"
|
||||
(buttonClick)="onClickFab($event)"
|
||||
>
|
||||
<div *ngIf="tabIndex === 'group'" ucapFloatActionButton="mainIcon">
|
||||
<div
|
||||
*ngIf="curNavi === NavigationType.Group"
|
||||
ucapFloatActionButton="mainIcon"
|
||||
>
|
||||
<mat-icon class="ico-font-float">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
@ -303,7 +311,10 @@
|
|||
</svg>
|
||||
</mat-icon>
|
||||
</div>
|
||||
<div *ngIf="tabIndex === 'chat'" ucapFloatActionButton="mainIcon">
|
||||
<div
|
||||
*ngIf="curNavi === NavigationType.Chat"
|
||||
ucapFloatActionButton="mainIcon"
|
||||
>
|
||||
<mat-icon class="ico-font-float">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
@ -341,7 +352,7 @@
|
|||
</mat-icon>
|
||||
</div>
|
||||
<div
|
||||
*ngIf="tabIndex === 'message'"
|
||||
*ngIf="curNavi === NavigationType.Message"
|
||||
ucapFloatActionButton="mainIcon"
|
||||
>
|
||||
<mat-icon class="ico-font-float">
|
||||
|
@ -381,7 +392,10 @@
|
|||
</svg>
|
||||
</mat-icon>
|
||||
</div>
|
||||
<div *ngIf="tabIndex === 'call'" ucapFloatActionButton="mainIcon">
|
||||
<div
|
||||
*ngIf="curNavi === NavigationType.Call"
|
||||
ucapFloatActionButton="mainIcon"
|
||||
>
|
||||
<mat-icon class="ico-font-dialpad">dialpad</mat-icon>
|
||||
</div>
|
||||
</ucap-float-action-button>
|
||||
|
@ -400,8 +414,10 @@
|
|||
<div class="content-sidenav-top-bar" fxFlex="0 0 40px">
|
||||
<app-layouts-top-bar>
|
||||
<div class="content-sidenav-top-bar-content">
|
||||
<div class="toolbar-info-area date-info">
|
||||
<span>Today</span>{{ moment().format('YYYY.MM.DD') }}
|
||||
<div class="toolbar-info-area date-info toolbar-drag-area">
|
||||
<div class="today">
|
||||
<span>Today</span>{{ moment().format('YYYY.MM.DD') }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="toolbar-info-area toolbar-ctrl">
|
||||
<!--Search-->
|
||||
|
@ -418,15 +434,12 @@
|
|||
<!--My Profile -->
|
||||
<div
|
||||
class="my-profile"
|
||||
matTooltip="프로필 버튼"
|
||||
matTooltipPosition="below"
|
||||
matTooltipHideDelay="1000"
|
||||
[matMenuTriggerFor]="profileMenu"
|
||||
#profileMenuTrigger="matMenuTrigger"
|
||||
>
|
||||
<app-organization-profile-image-01
|
||||
[userInfo]="user.info"
|
||||
[versionInfo]="versionInfo2Res"
|
||||
[versionInfo]="versionInfo"
|
||||
(openProfile)="onOpenProfile($event)"
|
||||
></app-organization-profile-image-01>
|
||||
</div>
|
||||
|
@ -445,7 +458,9 @@
|
|||
<!--Footer-->
|
||||
<div class="footer">
|
||||
<div class="foot-info version-info">
|
||||
<span class="var-txt current-ver">현재버전 0.0.11</span>
|
||||
<span class="var-txt current-ver" (click)="onClickForOpenRoom()"
|
||||
>현재버전 0.0.11</span
|
||||
>
|
||||
<span class="var-txt new-var">최신버전 0.0.11 </span>
|
||||
<button mat-icon-button aria-label="icon">
|
||||
<mat-icon>get_app</mat-icon>
|
||||
|
|
|
@ -8,13 +8,23 @@
|
|||
.layout-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
&.electron {
|
||||
border: 1px solid #aaa;
|
||||
}
|
||||
|
||||
.navitab-page {
|
||||
//GNB /////////////////////////////////////
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
width: 60px;
|
||||
@include screen(xs) {
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
.gnb {
|
||||
//background-color: $gray-ref0;
|
||||
background-color: #f1f2f6;
|
||||
width: 60px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -25,7 +35,7 @@
|
|||
flex-basis: 40px;
|
||||
padding: 2px 12px 10px;
|
||||
.img-logo {
|
||||
margin: 6px 0 0 1px;
|
||||
margin: 10px 0 0 1px;
|
||||
}
|
||||
}
|
||||
.left-container {
|
||||
|
@ -62,7 +72,7 @@
|
|||
content: '';
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
background-image: url(../../../assets/images/ico/btn_gnb_hompage.svg);
|
||||
background-image: url(/assets/images/ico/btn_gnb_hompage.svg);
|
||||
background-size: 30px;
|
||||
display: block;
|
||||
position: absolute;
|
||||
|
@ -112,6 +122,9 @@
|
|||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 16px;
|
||||
-webkit-app-region: drag;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -134,36 +147,53 @@
|
|||
justify-content: space-between;
|
||||
.toolbar-info-area {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
align-items: center;
|
||||
&.toolbar-drag-area {
|
||||
-webkit-app-region: drag;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
&.date-info {
|
||||
@include font-family($font-light);
|
||||
font-weight: 600;
|
||||
font-size: 12px;
|
||||
color: $gray-re70;
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
padding-left: 30px;
|
||||
height: 100%;
|
||||
@include screen(mid) {
|
||||
padding-left: 16px;
|
||||
display: none;
|
||||
}
|
||||
span {
|
||||
width: 54px;
|
||||
height: 16px;
|
||||
border-radius: 30px;
|
||||
border: solid 1px $lipstick;
|
||||
background-color: #ffffff;
|
||||
font-size: 11px;
|
||||
|
||||
.today {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: $lipstick;
|
||||
margin-right: 8px;
|
||||
span {
|
||||
width: 54px;
|
||||
height: 16px;
|
||||
border-radius: 30px;
|
||||
border: solid 1px $lipstick;
|
||||
background-color: #ffffff;
|
||||
font-size: 11px;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: $lipstick;
|
||||
margin-right: 8px;
|
||||
}
|
||||
@include screen(mid) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.toolbar-ctrl {
|
||||
flex-flow: row-reverse;
|
||||
margin-left: auto;
|
||||
.topbar-search {
|
||||
//개발예정으로 개발후 오픈
|
||||
display: none;
|
||||
order: 2;
|
||||
margin-right: 8px;
|
||||
.ico-search-icon {
|
||||
|
@ -175,8 +205,8 @@
|
|||
}
|
||||
}
|
||||
.my-profile {
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
height: 28px;
|
||||
width: 28px;
|
||||
margin-right: 20px;
|
||||
order: 1;
|
||||
//profile /////////////
|
||||
|
@ -239,6 +269,7 @@
|
|||
@include font-family($font-light);
|
||||
font-weight: 600;
|
||||
&.version-info {
|
||||
display: none;
|
||||
.var-txt {
|
||||
padding-left: 8px;
|
||||
color: $gray-re70;
|
||||
|
|
|
@ -3,7 +3,7 @@ import moment from 'moment';
|
|||
import { Subject, of } from 'rxjs';
|
||||
import { takeUntil, filter, take, map, catchError } from 'rxjs/operators';
|
||||
|
||||
import { Component, ViewChild, OnDestroy, OnInit } from '@angular/core';
|
||||
import { Component, ViewChild, OnDestroy, OnInit, Inject } from '@angular/core';
|
||||
import {
|
||||
Router,
|
||||
RouterEvent,
|
||||
|
@ -20,23 +20,43 @@ import { MatMenuTrigger } from '@angular/material/menu';
|
|||
import { MatTabChangeEvent, MatTabGroup } from '@angular/material/tabs';
|
||||
import { MatSidenav } from '@angular/material/sidenav';
|
||||
|
||||
import { VersionInfo2Response } from '@ucap/api-public';
|
||||
import { UserInfoSS } from '@ucap/protocol-query';
|
||||
import { User, UserInfoSS } from '@ucap/domain-organization';
|
||||
|
||||
import { LogService } from '@ucap/ng-logger';
|
||||
import { UserSelector } from '@ucap/ng-store-organization';
|
||||
import { ConfigurationSelector } from '@ucap/ng-store-authentication';
|
||||
import { RoomSelector } from '@ucap/ng-store-chat';
|
||||
|
||||
import { AppSelector } from '@app/store/state';
|
||||
import { AppChatService } from '@app/services/app-chat.service';
|
||||
import { QueryParams as ChatQueryParams } from '@app/pages/chat/types/params.type';
|
||||
import { CreateDialogComponent } from '@app/sections/group/dialogs/create.dialog.component';
|
||||
import { AppAccountService } from '@app/services/app-account.service';
|
||||
import { AppCallService } from '@app/services/app-call.service';
|
||||
import { AppUiService } from '@app/services/app-ui.service';
|
||||
import { QueryParams as OrganizationParams } from '@app/pages/organization/types/params.type';
|
||||
import { User } from '@ucap/protocol-info';
|
||||
import { AddUserDialogComponent } from '@app/sections/group/dialogs/add-user.dialog.component';
|
||||
import {
|
||||
CreateDialogComponent as ChatCreateDialogComponent,
|
||||
CreateDialogData as ChatCreateDialogData,
|
||||
CreateDialogResult as ChatCreateDialogResult
|
||||
} from '@app/sections/chat/dialogs/create.dialog.component';
|
||||
import { UCAP_NATIVE_SERVICE } from '@ucap/ng-native';
|
||||
import { NativeService } from '@ucap/native';
|
||||
import { AppActions } from '@app/store/actions';
|
||||
import { NavigationType } from '@app/types';
|
||||
import { I18nService } from '@ucap/ng-i18n';
|
||||
import {
|
||||
DialpadDialogComponent,
|
||||
DialpadDialogData,
|
||||
DialpadDialogResult
|
||||
} from '@app/sections/call/dialogs/dialpad.dialog.component';
|
||||
import { VersionInfo } from '@ucap/domain-authentication';
|
||||
|
||||
const NAVS = ['group', 'chat', 'organization', 'message'];
|
||||
const NAVS = [
|
||||
NavigationType.Group,
|
||||
NavigationType.Chat,
|
||||
NavigationType.Organization,
|
||||
NavigationType.Message,
|
||||
NavigationType.Call
|
||||
];
|
||||
|
||||
@Component({
|
||||
selector: 'app-layouts-default',
|
||||
|
@ -48,16 +68,21 @@ export class DefaultLayoutComponent implements OnInit, OnDestroy {
|
|||
navTabGroup: MatTabGroup;
|
||||
|
||||
@ViewChild('leftSidenav', { static: true })
|
||||
leftSidenav: MatSidenav;
|
||||
|
||||
isShowLeftSideNav = false;
|
||||
set leftSidenav(leftSidenav: MatSidenav) {
|
||||
this._leftSidenav = leftSidenav;
|
||||
this.appUiService.leftSidenav = leftSidenav;
|
||||
}
|
||||
get leftSidenav(): MatSidenav {
|
||||
return this._leftSidenav;
|
||||
}
|
||||
// tslint:disable-next-line: variable-name
|
||||
_leftSidenav: MatSidenav;
|
||||
|
||||
@ViewChild('profileMenuTrigger', { static: true })
|
||||
profileMenuTrigger: MatMenuTrigger;
|
||||
|
||||
showStatusbar = true;
|
||||
|
||||
tabIndex: string;
|
||||
queryParams: Params;
|
||||
|
||||
unreadCountChat = 0;
|
||||
|
@ -66,23 +91,30 @@ export class DefaultLayoutComponent implements OnInit, OnDestroy {
|
|||
fabButtonShow = true;
|
||||
fabUseCustomDefaultIcon = true; // default in this prj
|
||||
fabButtons: { icon: string; tooltip?: string; divisionType?: string }[];
|
||||
versionInfo2Res: VersionInfo2Response;
|
||||
versionInfo: VersionInfo;
|
||||
user: User;
|
||||
|
||||
/** Navigation */
|
||||
NavigationType = NavigationType;
|
||||
initMenu = NavigationType.Group;
|
||||
curNavi: NavigationType;
|
||||
|
||||
moment = moment;
|
||||
|
||||
private ngOnDestroySubject: Subject<void> = new Subject();
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private i18nSevice: I18nService,
|
||||
private activatedRoute: ActivatedRoute,
|
||||
private store: Store<any>,
|
||||
private appAccountService: AppAccountService,
|
||||
private appChatService: AppChatService,
|
||||
private appCallService: AppCallService,
|
||||
private appUiService: AppUiService,
|
||||
private logService: LogService,
|
||||
public dialog: MatDialog
|
||||
public dialog: MatDialog,
|
||||
@Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService
|
||||
) {
|
||||
this.setFabInitial(NAVS[0]);
|
||||
this.setFabInitial(this.initMenu);
|
||||
this.router.events
|
||||
.pipe(
|
||||
takeUntil(this.ngOnDestroySubject),
|
||||
|
@ -97,7 +129,7 @@ export class DefaultLayoutComponent implements OnInit, OnDestroy {
|
|||
if (!p || !p.segments || 0 === p.segments.length) {
|
||||
break;
|
||||
}
|
||||
const index = p.segments[0].path;
|
||||
const index = p.segments[0].path as NavigationType;
|
||||
this.setTabGroup(index);
|
||||
this.setFabInitial(index);
|
||||
}
|
||||
|
@ -116,32 +148,14 @@ export class DefaultLayoutComponent implements OnInit, OnDestroy {
|
|||
this.store
|
||||
.pipe(
|
||||
takeUntil(this.ngOnDestroySubject),
|
||||
select(ConfigurationSelector.versionInfo2Response)
|
||||
select(ConfigurationSelector.versionInfo)
|
||||
)
|
||||
.subscribe((versionInfo2Res) => {
|
||||
this.versionInfo2Res = versionInfo2Res;
|
||||
.subscribe((versionInfo) => {
|
||||
this.versionInfo = versionInfo;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.store
|
||||
.pipe(takeUntil(this.ngOnDestroySubject), select(AppSelector.windowSize))
|
||||
.subscribe((size) => {
|
||||
if (size.width < 780) {
|
||||
if (this.leftSidenav.opened) {
|
||||
this.leftSidenav.close();
|
||||
}
|
||||
this.isShowLeftSideNav = false;
|
||||
this.leftSidenav.mode = 'over';
|
||||
} else {
|
||||
if (!this.leftSidenav.opened) {
|
||||
this.leftSidenav.open();
|
||||
}
|
||||
this.isShowLeftSideNav = true;
|
||||
this.leftSidenav.mode = 'side';
|
||||
}
|
||||
});
|
||||
|
||||
this.store
|
||||
.pipe(takeUntil(this.ngOnDestroySubject), select(UserSelector.user))
|
||||
.subscribe((user) => {
|
||||
|
@ -156,6 +170,31 @@ export class DefaultLayoutComponent implements OnInit, OnDestroy {
|
|||
.subscribe((unreadTotal) => {
|
||||
this.unreadCountChat = unreadTotal;
|
||||
});
|
||||
|
||||
// this.store
|
||||
// .pipe(
|
||||
// takeUntil(this.ngOnDestroySubject),
|
||||
// select(PresenceSelector.selectAllStatusBulkInfo)
|
||||
// )
|
||||
// .subscribe((allBulkInfo) => {
|
||||
// // .includes(String(this.user.info.seq))
|
||||
// if (!allBulkInfo || (!!allBulkInfo && allBulkInfo.length === 0)) {
|
||||
// return;
|
||||
// }
|
||||
// const userStatusinfo = allBulkInfo.filter(
|
||||
// (bulkInfo) => bulkInfo.userSeq === String(this.user.info.seq)
|
||||
// )[0];
|
||||
|
||||
// const status = PresenceUtil.isOnline(userStatusinfo, PresenceType.PC);
|
||||
// if (!status && userStatusinfo.pcStatus === StatusCode.Offline) {
|
||||
// this.store.dispatch(
|
||||
// PresenceActions.bulkInfo({
|
||||
// divCd: 'myBulk',
|
||||
// userSeqs: [String(this.user.info.seq)]
|
||||
// })
|
||||
// );
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
|
@ -170,14 +209,13 @@ export class DefaultLayoutComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
onSelectedTabChange(event: MatTabChangeEvent) {
|
||||
const commands: any = [
|
||||
NAVS[event.index],
|
||||
{ outlets: { content: 'index' } }
|
||||
];
|
||||
const naviMenu: NavigationType = event.tab.ariaLabel as NavigationType;
|
||||
const commands: any = [naviMenu, { outlets: { content: 'index' } }];
|
||||
const orgInitialParams: Params = {};
|
||||
|
||||
// CASE :: Chat.
|
||||
if (
|
||||
event.index === 1 && // is chat.
|
||||
naviMenu === NavigationType.Chat && // is chat.
|
||||
!!this.queryParams &&
|
||||
!!this.queryParams[ChatQueryParams.ROOM_ID]
|
||||
) {
|
||||
|
@ -185,55 +223,45 @@ export class DefaultLayoutComponent implements OnInit, OnDestroy {
|
|||
this.queryParams = undefined;
|
||||
return;
|
||||
}
|
||||
// if (!!this.tabIndex && this.tabIndex === 'chat') {
|
||||
// if (!!this.queryParams && !!this.queryParams[ChatQueryParams.ROOM_ID]) {
|
||||
// return;
|
||||
// } else {
|
||||
|
||||
// }
|
||||
// } else {
|
||||
// }
|
||||
|
||||
if (event.index === 2 && !!this.user) {
|
||||
// CASE :: Organization.
|
||||
if (naviMenu === NavigationType.Organization && !!this.user) {
|
||||
orgInitialParams[OrganizationParams.DEPT_SEQ] = String(
|
||||
this.user.departmentCode
|
||||
);
|
||||
}
|
||||
|
||||
this.router.navigate(commands, { queryParams: orgInitialParams });
|
||||
if (!this.isShowLeftSideNav) {
|
||||
this.leftSidenav.open();
|
||||
}
|
||||
this.setFabInitial(NAVS[event.index]);
|
||||
this.appUiService.openLeftSidenavOnNarrowMode();
|
||||
this.setFabInitial(naviMenu);
|
||||
}
|
||||
|
||||
onClickToggleLeftSidenav() {
|
||||
if (!this.isShowLeftSideNav) {
|
||||
this.leftSidenav.toggle();
|
||||
}
|
||||
this.appUiService.toggleLeftSidenavOnNarrowMode();
|
||||
}
|
||||
|
||||
setFabInitial(type: string) {
|
||||
this.tabIndex = type;
|
||||
setFabInitial(type: NavigationType) {
|
||||
this.curNavi = type;
|
||||
switch (type) {
|
||||
case 'group':
|
||||
case NavigationType.Group:
|
||||
{
|
||||
this.fabButtonShow = true;
|
||||
this.fabButtons = [
|
||||
{
|
||||
icon: 'add',
|
||||
tooltip: '그룹 추가',
|
||||
tooltip: this.i18nSevice.t('group:dialog.title.addNewBuddy'),
|
||||
divisionType: 'GROUP_NEW_ADD'
|
||||
}
|
||||
];
|
||||
}
|
||||
break;
|
||||
case 'chat':
|
||||
case NavigationType.Chat:
|
||||
{
|
||||
this.fabButtonShow = true;
|
||||
this.fabButtons = [
|
||||
{
|
||||
icon: 'chat',
|
||||
tooltip: '대화 추가',
|
||||
tooltip: this.i18nSevice.t('chat:dialog.title.newChatRoom'),
|
||||
divisionType: 'CAHT_NEW_ADD'
|
||||
}
|
||||
];
|
||||
|
@ -247,12 +275,12 @@ export class DefaultLayoutComponent implements OnInit, OnDestroy {
|
|||
// }
|
||||
}
|
||||
break;
|
||||
case 'organization':
|
||||
case NavigationType.Organization:
|
||||
{
|
||||
this.fabButtonShow = false;
|
||||
}
|
||||
break;
|
||||
case 'message':
|
||||
case NavigationType.Message:
|
||||
{
|
||||
this.fabButtonShow = true;
|
||||
this.fabButtons = [
|
||||
|
@ -264,11 +292,18 @@ export class DefaultLayoutComponent implements OnInit, OnDestroy {
|
|||
];
|
||||
}
|
||||
break;
|
||||
// case MainMenu.Call:
|
||||
// {
|
||||
// this.fabButtonShow = false;
|
||||
// }
|
||||
// break;
|
||||
case NavigationType.Call:
|
||||
{
|
||||
this.fabButtonShow = true;
|
||||
this.fabButtons = [
|
||||
{
|
||||
icon: 'dialpad',
|
||||
tooltip: this.i18nSevice.t('call:label.dialpad'),
|
||||
divisionType: 'OPEN_DIALPAD'
|
||||
}
|
||||
];
|
||||
}
|
||||
break;
|
||||
|
||||
default: {
|
||||
this.fabButtonShow = false;
|
||||
|
@ -286,10 +321,14 @@ export class DefaultLayoutComponent implements OnInit, OnDestroy {
|
|||
switch (btn.divisionType) {
|
||||
case 'GROUP_NEW_ADD':
|
||||
{
|
||||
const dialogRef = this.dialog.open(CreateDialogComponent, {
|
||||
const dialogRef = this.dialog.open(AddUserDialogComponent, {
|
||||
panelClass: 'max-create-dialog'
|
||||
});
|
||||
|
||||
dialogRef
|
||||
.afterOpened()
|
||||
.pipe(take(1))
|
||||
.subscribe(() => dialogRef.componentInstance.psUpdate());
|
||||
dialogRef
|
||||
.afterClosed()
|
||||
.pipe(
|
||||
|
@ -304,7 +343,14 @@ export class DefaultLayoutComponent implements OnInit, OnDestroy {
|
|||
break;
|
||||
case 'CAHT_NEW_ADD':
|
||||
{
|
||||
this.appChatService.newOpenRoomDialog();
|
||||
const dialogRef = this.dialog.open<
|
||||
ChatCreateDialogComponent,
|
||||
ChatCreateDialogData,
|
||||
ChatCreateDialogResult
|
||||
>(ChatCreateDialogComponent, {
|
||||
panelClass: 'max-create-dialog',
|
||||
data: {}
|
||||
});
|
||||
}
|
||||
break;
|
||||
case 'CHAT_NEW_TIMER_ADD':
|
||||
|
@ -320,6 +366,19 @@ export class DefaultLayoutComponent implements OnInit, OnDestroy {
|
|||
this.logService.debug('MESSAGE_NEW');
|
||||
}
|
||||
break;
|
||||
|
||||
case 'OPEN_DIALPAD':
|
||||
{
|
||||
this.dialog.open<
|
||||
DialpadDialogComponent,
|
||||
DialpadDialogData,
|
||||
DialpadDialogResult
|
||||
>(DialpadDialogComponent, {
|
||||
panelClass: 'mid-create-dialog',
|
||||
data: {}
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -350,9 +409,21 @@ export class DefaultLayoutComponent implements OnInit, OnDestroy {
|
|||
this.profileMenuTrigger.closeMenu();
|
||||
}
|
||||
|
||||
onClickForOpenRoom() {
|
||||
this.nativeService.chat_openRoom('/chat/chatroom?roomId=1000');
|
||||
}
|
||||
|
||||
private setTabGroup(url: string) {
|
||||
if (!!this.navTabGroup) {
|
||||
this.navTabGroup.selectedIndex = NAVS.findIndex((v) => url === v);
|
||||
}
|
||||
}
|
||||
|
||||
onOpenStart(opened: boolean) {
|
||||
this.store.dispatch(
|
||||
AppActions.openedLiftSideNav({
|
||||
opened
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<div class="layout-container" fxFlexFill fxLayout="column">
|
||||
<div *ngIf="showTopbar" class="top-bar" fxFlex="50px">
|
||||
<app-layouts-top-bar></app-layouts-top-bar>
|
||||
<app-layouts-top-bar class="no-navi-top-bar"></app-layouts-top-bar>
|
||||
</div>
|
||||
<div class="layout-content" fxFlex="1 1 auto">
|
||||
<router-outlet></router-outlet>
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
<div class="title-bar">
|
||||
<ucap-title-bar
|
||||
[platform]="platform"
|
||||
(closed)="onClosedTitleBar()"
|
||||
(maximized)="onMaximizedTitleBar()"
|
||||
(minimized)="onMinimizedTitleBar()"
|
||||
[windowState]="windowState"
|
||||
(closed)="onClosed()"
|
||||
(maximized)="onMaximized($event)"
|
||||
(minimized)="onMinimized()"
|
||||
>
|
||||
<ng-content></ng-content>
|
||||
</ucap-title-bar>
|
||||
|
|
|
@ -67,9 +67,15 @@ export class TopBarComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
}
|
||||
|
||||
onClosedTitleBar() {}
|
||||
onClosed() {
|
||||
this.nativeService.window_close();
|
||||
}
|
||||
|
||||
onMaximizedTitleBar() {}
|
||||
onMaximized(altKey: boolean) {
|
||||
this.nativeService.window_maximize(altKey);
|
||||
}
|
||||
|
||||
onMinimizedTitleBar() {}
|
||||
onMinimized() {
|
||||
this.nativeService.window_minimize();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,9 @@ import { MatTooltipModule } from '@angular/material/tooltip';
|
|||
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
|
||||
|
||||
import { I18nModule, UCAP_I18N_NAMESPACE } from '@ucap/ng-i18n';
|
||||
import { UiModule } from '@ucap/ng-ui';
|
||||
|
||||
import { UiButtonModule } from '@ucap/ng-ui/button';
|
||||
import { UiNativeModule } from '@ucap/ng-ui/native';
|
||||
|
||||
import { AppOrganizationModule } from '@app/ucap/organization/organization.module';
|
||||
|
||||
|
@ -45,7 +47,9 @@ import { DIALOGS } from './dialogs';
|
|||
PerfectScrollbarModule,
|
||||
|
||||
I18nModule,
|
||||
UiModule,
|
||||
|
||||
UiButtonModule,
|
||||
UiNativeModule,
|
||||
|
||||
AppOrganizationModule
|
||||
],
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
import { SortViewType } from '@app/pages/group/types/sort-view.type';
|
||||
|
||||
export interface GroupOpenInfo {
|
||||
lastGroupSeq: number;
|
||||
groupSeqs: number[];
|
||||
showType: SortViewType;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { LoginSession as UCAPLoginSession } from '@ucap/core';
|
||||
import { LoginSession as UCAPLoginSession } from '@ucap/domain-authentication';
|
||||
import { GroupOpenInfo } from './group-open-info';
|
||||
|
||||
export interface LoginSession extends UCAPLoginSession {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import {
|
||||
GeneralSetting as UCAPGeneralSetting,
|
||||
NotificationSetting as UCAPNotificationSetting,
|
||||
ChatSetting as UCAPChatSetting,
|
||||
PresenceSetting as UCAPPresenceSetting
|
||||
} from '@ucap/protocol-option';
|
||||
NotificationSetting as UCAPNotificationSetting
|
||||
} from '@ucap/domain-common';
|
||||
import { PresenceSetting as UCAPPresenceSetting } from '@ucap/domain-status';
|
||||
import { ChatSetting as UCAPChatSetting } from '@ucap/domain-chat';
|
||||
|
||||
// tslint:disable-next-line: no-empty-interface
|
||||
export interface GeneralSetting extends UCAPGeneralSetting {}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { UserStore as UCAPUserStore } from '@ucap/core';
|
||||
import { UserStore as UCAPUserStore } from '@ucap/domain-authentication';
|
||||
|
||||
import { Settings } from './settings';
|
||||
|
||||
|
|
|
@ -14,25 +14,25 @@ $login-bg-h: 100/1080;
|
|||
justify-content: center;
|
||||
|
||||
background-color: $bg-gray;
|
||||
background-image: url(../../../../assets/images/bg/bg_login_circle_square01.svg),
|
||||
url(../../../../assets/images/bg/bg_login_circle_stroke01.svg),
|
||||
url(../../../../assets/images/bg/bg_login_circle01.svg),
|
||||
url(../../../../assets/images/bg/bg_login_circle03.svg),
|
||||
url(../../../../assets/images/bg/bg_login_circle_diagonal01.svg),
|
||||
url(../../../../assets/images/bg/bg_login_circle_square02.svg),
|
||||
url(../../../../assets/images/bg/bg_login_circle04.svg),
|
||||
url(../../../../assets/images/bg/bg_login_circle05.svg),
|
||||
url(../../../../assets/images/bg/bg_login_circle06.svg),
|
||||
url(../../../../assets/images/bg/bg_login_circle07.svg),
|
||||
url(../../../../assets/images/bg/bg_login_circle08.svg),
|
||||
url(../../../../assets/images/bg/bg_login_circle_diagonal02.svg),
|
||||
url(../../../../assets/images/bg/bg_login_circle_diagonal03.svg),
|
||||
url(../../../../assets/images/bg/bg_login_circle_stroke02.svg),
|
||||
url(../../../../assets/images/bg/bg_login_circle_stroke03.svg),
|
||||
url(../../../../assets/images/bg/bg_login_circle_stroke04.svg),
|
||||
url(../../../../assets/images/bg/bg_login_circle_stroke05.svg),
|
||||
url(../../../../assets/images/bg/bg_login_polygon01.svg),
|
||||
url(../../../../assets/images/bg/bg_login_polygon02.svg);
|
||||
background-image: url(/assets/images/bg/bg_login_circle_square01.svg),
|
||||
url(/assets/images/bg/bg_login_circle_stroke01.svg),
|
||||
url(/assets/images/bg/bg_login_circle01.svg),
|
||||
url(/assets/images/bg/bg_login_circle03.svg),
|
||||
url(/assets/images/bg/bg_login_circle_diagonal01.svg),
|
||||
url(/assets/images/bg/bg_login_circle_square02.svg),
|
||||
url(/assets/images/bg/bg_login_circle04.svg),
|
||||
url(/assets/images/bg/bg_login_circle05.svg),
|
||||
url(/assets/images/bg/bg_login_circle06.svg),
|
||||
url(/assets/images/bg/bg_login_circle07.svg),
|
||||
url(/assets/images/bg/bg_login_circle08.svg),
|
||||
url(/assets/images/bg/bg_login_circle_diagonal02.svg),
|
||||
url(/assets/images/bg/bg_login_circle_diagonal03.svg),
|
||||
url(/assets/images/bg/bg_login_circle_stroke02.svg),
|
||||
url(/assets/images/bg/bg_login_circle_stroke03.svg),
|
||||
url(/assets/images/bg/bg_login_circle_stroke04.svg),
|
||||
url(/assets/images/bg/bg_login_circle_stroke05.svg),
|
||||
url(/assets/images/bg/bg_login_polygon01.svg),
|
||||
url(/assets/images/bg/bg_login_polygon02.svg);
|
||||
background-repeat: no-repeat;
|
||||
background-position: unquote($login-bg-w * 323 + '%')
|
||||
unquote($login-bg-h * 179 + '%'),
|
||||
|
|
|
@ -1 +1,22 @@
|
|||
<div class="logout-container">Logout</div>
|
||||
<div class="logout-container">
|
||||
<div class="logout-content">
|
||||
<div class="logout-title"></div>
|
||||
|
||||
<p class="guide-text">
|
||||
서비스를 이용하시려면 다시 로그인하여 주시기 바랍니다.<br />
|
||||
<span
|
||||
>항상 더 좋은 서비스로 고객님께 보답하는 M-Messenger가 되겠습니다.</span
|
||||
>
|
||||
</p>
|
||||
|
||||
<!--<p class="guide-text">
|
||||
다른 기기에서 동일한 계정으로 로그인되었습니다.<br />본인이 아닌 경우
|
||||
비밀번호 변경을 하시기 바랍니다.
|
||||
<span
|
||||
>항상 더 좋은 서비스로 고객님께 보답하는 M-Messenger가 되겠습니다.</span
|
||||
>
|
||||
</p>-->
|
||||
|
||||
<span class="guide-move">OO초 후 로그인 페이지로 자동 이동 됩니다 </span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -3,4 +3,57 @@
|
|||
.logout-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: #f3f4f5;
|
||||
background-image: url(/assets/images/ico/img_logout.png);
|
||||
background-position: 50% bottom;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 90% auto;
|
||||
@include screen(xs) {
|
||||
background-size: 100% auto;
|
||||
}
|
||||
|
||||
.logout-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
max-width: 80%;
|
||||
transform: translateY(-70%);
|
||||
.logout-title {
|
||||
display: block;
|
||||
width: 250px;
|
||||
height: 62px;
|
||||
text-align: center;
|
||||
background: url(/assets/images/ico/img_logout_text.svg);
|
||||
}
|
||||
|
||||
.guide-text {
|
||||
font-size: 1.6em;
|
||||
color: #666;
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
@include screen(xs) {
|
||||
font-size: 1.4em;
|
||||
}
|
||||
|
||||
span {
|
||||
display: inline-flex;
|
||||
font-size: 0.7em;
|
||||
color: #999;
|
||||
font-weight: normal;
|
||||
margin-top: 0.7em;
|
||||
}
|
||||
}
|
||||
|
||||
.guide-move {
|
||||
display: inline-flex;
|
||||
padding: 0.8em 1.4em;
|
||||
border-radius: 100px;
|
||||
background-color: #fd578a;
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,12 +3,19 @@ import { Routes, RouterModule } from '@angular/router';
|
|||
|
||||
import { IndexPageComponent } from './components/index.page.component';
|
||||
import { SidenavPageComponent } from './components/sidenav.page.component';
|
||||
import { CallHistoryPageComponent } from './components/call-history.page.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: 'index',
|
||||
outlet: 'content',
|
||||
component: IndexPageComponent
|
||||
// component: IndexPageComponent
|
||||
component: CallHistoryPageComponent
|
||||
},
|
||||
{
|
||||
path: 'callhistory',
|
||||
outlet: 'content',
|
||||
component: CallHistoryPageComponent
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
|
|
|
@ -3,18 +3,52 @@ import { CommonModule } from '@angular/common';
|
|||
|
||||
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatTabsModule } from '@angular/material/tabs';
|
||||
|
||||
import { UiDateModule } from '@ucap/ng-ui/date';
|
||||
import { UiPhoneModule } from '@ucap/ng-ui/phone';
|
||||
|
||||
import { I18nModule, UCAP_I18N_NAMESPACE } from '@ucap/ng-i18n';
|
||||
import { OrganizationUiModule } from '@ucap/ng-ui-organization';
|
||||
|
||||
import { AppOrganizationModule } from '@app/ucap/organization/organization.module';
|
||||
import { AppCallSectionModule } from '@app/sections/call/call.section.module';
|
||||
|
||||
import { AppCallRoutingPageModule } from './call-routing.page.module';
|
||||
|
||||
import { IndexPageComponent } from './components/index.page.component';
|
||||
import { SidenavPageComponent } from './components/sidenav.page.component';
|
||||
|
||||
export const COMPONENTS = [IndexPageComponent, SidenavPageComponent];
|
||||
|
||||
export { IndexPageComponent, SidenavPageComponent };
|
||||
import { COMPONENTS } from './components';
|
||||
import { AppGroupModule } from '@app/ucap/group/group.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, FlexLayoutModule, AppCallRoutingPageModule],
|
||||
imports: [
|
||||
CommonModule,
|
||||
FlexLayoutModule,
|
||||
|
||||
MatButtonModule,
|
||||
MatIconModule,
|
||||
MatTabsModule,
|
||||
|
||||
I18nModule,
|
||||
|
||||
UiDateModule,
|
||||
UiPhoneModule,
|
||||
|
||||
OrganizationUiModule,
|
||||
|
||||
AppOrganizationModule,
|
||||
|
||||
AppCallSectionModule,
|
||||
AppCallRoutingPageModule,
|
||||
AppGroupModule
|
||||
],
|
||||
declarations: [...COMPONENTS],
|
||||
entryComponents: []
|
||||
entryComponents: [],
|
||||
providers: [
|
||||
{
|
||||
provide: UCAP_I18N_NAMESPACE,
|
||||
useValue: ['call', 'common']
|
||||
}
|
||||
]
|
||||
})
|
||||
export class AppCallPageModule {}
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
<div class="contents-main" fxFlexFill fxLayout="column">
|
||||
<div class="subtitle" fxFlex="0 0 50px" fxLayout="row">
|
||||
<div class="title">{{ 'call:label.callHistory' | ucapI18n }}</div>
|
||||
<div class="call-info" fxLayout="row">
|
||||
<div class="info send">
|
||||
<mat-icon>call_made</mat-icon>{{ 'call:label.send' | ucapI18n }}
|
||||
</div>
|
||||
<div class="info receive">
|
||||
<mat-icon>call_received</mat-icon>{{ 'call:label.recieve' | ucapI18n }}
|
||||
</div>
|
||||
<div class="info away">
|
||||
<mat-icon>call_missed</mat-icon>{{ 'call:label.missed' | ucapI18n }}
|
||||
</div>
|
||||
<div class="info unanswered">
|
||||
<mat-icon>call_missed_outgoing</mat-icon
|
||||
>{{ 'call:label.unanswered' | ucapI18n }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="user-title" fxFlex="0 0 90px" fxLayout="row">
|
||||
<div class="user-profile-info">
|
||||
<div class="profile-image">
|
||||
<app-group-profile-image-01
|
||||
[userInfo]="userInfo"
|
||||
[versionInfo]="versionInfo"
|
||||
(openProfile)="onOpenProfile($event)"
|
||||
></app-group-profile-image-01>
|
||||
</div>
|
||||
<div class="user-info">
|
||||
<div class="user-n-g">
|
||||
<div class="user-name">
|
||||
{{ userInfo | ucapOrganizationTranslate: 'name':undefined:'' }}
|
||||
</div>
|
||||
<div class="user-grade">
|
||||
{{ userInfo | ucapOrganizationTranslate: 'grade':undefined:' ' }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="dept-name">
|
||||
{{ userInfo | ucapOrganizationTranslate: 'deptName':undefined:' ' }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="user-call-info" fxLayout="row">
|
||||
<div *ngIf="!!userInfo && !!userInfo.hpNumber" class="mobile">
|
||||
{{ userInfo.hpNumber | ucapPhoneNumber }}
|
||||
<img src="assets/images/ico/btn_list_mobile_a24.svg" alt="" />
|
||||
</div>
|
||||
<div *ngIf="!!userInfo && !!userInfo.lineNumber" class="lineNumber">
|
||||
{{ userInfo.lineNumber | ucapPhoneNumber }}
|
||||
<img src="assets/images/ico/btn_list_call_a24.svg" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="call-info-container" fxFlex="1 1 auto">
|
||||
<app-sections-call-info></app-sections-call-info>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,33 @@
|
|||
@import '~@ucap/lg-scss/mixins';
|
||||
|
||||
.contents-main {
|
||||
position: relative;
|
||||
.subtitle {
|
||||
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16);
|
||||
position: relative;
|
||||
z-index: 4;
|
||||
}
|
||||
.message-box-container {
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
.message-area {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
.message-input {
|
||||
max-height: 70%;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
padding: 1px 0;
|
||||
background-color: $white;
|
||||
}
|
||||
}
|
||||
.rightDrawer {
|
||||
min-width: 360px;
|
||||
max-width: 100%;
|
||||
@include screen(xs) {
|
||||
min-width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
import { TestBed, async } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { CallHistoryPageComponent } from './call-history.page.component';
|
||||
|
||||
describe('app::pages::chat::CallHistoryPageComponent', () => {
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [RouterTestingModule],
|
||||
declarations: [CallHistoryPageComponent]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
it('should create the app', () => {
|
||||
const fixture = TestBed.createComponent(CallHistoryPageComponent);
|
||||
const app = fixture.componentInstance;
|
||||
expect(app).toBeTruthy();
|
||||
});
|
||||
|
||||
it(`should have as title 'ucap-lg-web'`, () => {
|
||||
const fixture = TestBed.createComponent(CallHistoryPageComponent);
|
||||
const app = fixture.componentInstance;
|
||||
});
|
||||
|
||||
it('should render title', () => {
|
||||
const fixture = TestBed.createComponent(CallHistoryPageComponent);
|
||||
fixture.detectChanges();
|
||||
const compiled = fixture.nativeElement;
|
||||
expect(compiled.querySelector('.content span').textContent).toContain(
|
||||
'ucap-lg-web app is running!'
|
||||
);
|
||||
});
|
||||
});
|
129
src/app/pages/call/components/call-history.page.component.ts
Normal file
129
src/app/pages/call/components/call-history.page.component.ts
Normal file
|
@ -0,0 +1,129 @@
|
|||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
OnDestroy,
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef
|
||||
} from '@angular/core';
|
||||
import { ActivatedRoute, Params } from '@angular/router';
|
||||
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil, withLatestFrom } from 'rxjs/operators';
|
||||
import { QueryParams } from '../types/params.type';
|
||||
import { Store, select } from '@ngrx/store';
|
||||
|
||||
import { UserInfoSS } from '@ucap/domain-organization';
|
||||
|
||||
import { UserSelector } from '@ucap/ng-store-organization';
|
||||
import { AppOrganizationService } from '@app/services/app-organization.service';
|
||||
|
||||
import { ConfigurationSelector } from '@ucap/ng-store-authentication';
|
||||
|
||||
import {
|
||||
ProfileDialogComponent,
|
||||
ProfileDialogData,
|
||||
ProfileDialogResult
|
||||
} from '@app/sections/organization/dialogs/profile.dialog.component';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { VersionInfo } from '@ucap/domain-authentication';
|
||||
|
||||
@Component({
|
||||
selector: 'app-pages-call-history',
|
||||
templateUrl: './call-history.page.component.html',
|
||||
styleUrls: ['./call-history.page.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class CallHistoryPageComponent implements OnInit, OnDestroy {
|
||||
isMe: boolean;
|
||||
userSeq: string;
|
||||
userInfo: UserInfoSS;
|
||||
|
||||
versionInfo: VersionInfo;
|
||||
|
||||
private ngOnDestroySubject: Subject<void> = new Subject();
|
||||
constructor(
|
||||
private dialog: MatDialog,
|
||||
private store: Store<any>,
|
||||
private appOrganizationService: AppOrganizationService,
|
||||
private activatedRoute: ActivatedRoute,
|
||||
private changeDetectorRef: ChangeDetectorRef
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.activatedRoute.queryParams
|
||||
.pipe(
|
||||
takeUntil(this.ngOnDestroySubject),
|
||||
withLatestFrom(this.store.pipe(select(UserSelector.user)))
|
||||
)
|
||||
.subscribe(([params, user]) => {
|
||||
const seqParam = params[QueryParams.ID];
|
||||
|
||||
// initializing by userSeq Change.
|
||||
if (this.userSeq !== seqParam) {
|
||||
}
|
||||
|
||||
// setting userSeq.
|
||||
this.userSeq = !!seqParam
|
||||
? seqParam
|
||||
: !!user
|
||||
? String(user.info.seq)
|
||||
: undefined;
|
||||
|
||||
if (!!user && this.userSeq === String(user.info.seq)) {
|
||||
this.isMe = true;
|
||||
} else {
|
||||
this.isMe = false;
|
||||
}
|
||||
|
||||
if (!!this.userSeq) {
|
||||
const self = this;
|
||||
this.appOrganizationService
|
||||
.getUserInfo({ userSeq: this.userSeq, user })
|
||||
.then((result) => {
|
||||
console.log('getUserInfo : ', result);
|
||||
self.userInfo = result.userInfo;
|
||||
})
|
||||
.catch((e) => {
|
||||
self.userInfo = undefined;
|
||||
})
|
||||
.finally(() => {
|
||||
this.changeDetectorRef.markForCheck();
|
||||
});
|
||||
} else {
|
||||
this.userInfo = undefined;
|
||||
this.changeDetectorRef.markForCheck();
|
||||
}
|
||||
});
|
||||
|
||||
this.store
|
||||
.pipe(
|
||||
takeUntil(this.ngOnDestroySubject),
|
||||
select(ConfigurationSelector.versionInfo)
|
||||
)
|
||||
.subscribe((versionInfo) => {
|
||||
this.versionInfo = versionInfo;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (!!this.ngOnDestroySubject) {
|
||||
this.ngOnDestroySubject.next();
|
||||
this.ngOnDestroySubject.complete();
|
||||
}
|
||||
}
|
||||
|
||||
onOpenProfile(userInfo: UserInfoSS): void {
|
||||
if (!!userInfo) {
|
||||
this.dialog.open<
|
||||
ProfileDialogComponent,
|
||||
ProfileDialogData,
|
||||
ProfileDialogResult
|
||||
>(ProfileDialogComponent, {
|
||||
panelClass: 'mid-create-dialog',
|
||||
data: {
|
||||
userSeq: userInfo.seq
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1 +1,39 @@
|
|||
Index page of call is works!
|
||||
<div class="index-page-call-info">
|
||||
<div class="ico-page-call">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 166 142">
|
||||
<g transform="translate(-152.267 -127.865)">
|
||||
<path
|
||||
d="M0 0H166V142H0z"
|
||||
data-name="square-01"
|
||||
transform="translate(152.267 127.865)"
|
||||
style="fill: none;"
|
||||
/>
|
||||
<path
|
||||
d="M45.694 2a43.788 43.788 0 0 1 33.84 71.495l8.744 8.756a4.269 4.269 0 0 1-3.235 7.311H45.694a43.781 43.781 0 0 1 0-87.562z"
|
||||
data-name="comment-dots-01"
|
||||
transform="translate(199.283 158.998)"
|
||||
style="stroke: #bababa; stroke-width: 4px; fill: #fff;"
|
||||
/>
|
||||
<path
|
||||
d="M26.015 2A24.012 24.012 0 0 0 7.458 41.206l-4.8 4.8a2.341 2.341 0 0 0 1.774 4.009h21.583a24.009 24.009 0 0 0 0-48.015z"
|
||||
data-name="comment-dots-02"
|
||||
transform="translate(167.028 170.336)"
|
||||
style="fill: #999;"
|
||||
/>
|
||||
<path
|
||||
d="M33.725 5.917a5.628 5.628 0 1 1 11.242 0 5.628 5.628 0 1 1-11.242 0zm-16.862 0A5.775 5.775 0 0 1 22.483 0 5.775 5.775 0 0 1 28.1 5.917a5.774 5.774 0 0 1-5.621 5.917 5.774 5.774 0 0 1-5.617-5.917zM0 5.917A5.775 5.775 0 0 1 5.621 0a5.775 5.775 0 0 1 5.621 5.917 5.774 5.774 0 0 1-5.621 5.917A5.774 5.774 0 0 1 0 5.917z"
|
||||
transform="translate(223.585 197.682)"
|
||||
style="fill: #bababa;"
|
||||
/>
|
||||
<path
|
||||
d="M13.476 22.894l-7.509-6.82L3.41 18.38l10.066 9.143L35.086 7.9l-2.539-2.31z"
|
||||
transform="translate(174.515 180.942)"
|
||||
style="fill: #fff;"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
<p class="call-index-copy">
|
||||
{{ 'call:noSelectHistory' | ucapI18n }}
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
@import '~@ucap/lg-scss/mixins';
|
||||
.index-page-call-info {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
.ico-page-call {
|
||||
width: 166px;
|
||||
height: 142px;
|
||||
margin-top: -80px;
|
||||
}
|
||||
.call-index-copy {
|
||||
font-size: 1.429em;
|
||||
color: #666;
|
||||
padding: 10px 20px;
|
||||
border-top: 1px solid #ccc;
|
||||
border-bottom: 1px solid #ccc;
|
||||
margin: 50px 0 0;
|
||||
}
|
||||
@include screen(xs) {
|
||||
.ico-page-call {
|
||||
width: 120px;
|
||||
height: auto;
|
||||
margin-top: -40px;
|
||||
}
|
||||
.call-index-copy {
|
||||
font-size: 1.2em;
|
||||
margin: 20px 0 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,9 @@
|
|||
import { IndexPageComponent } from './index.page.component';
|
||||
import { SidenavPageComponent } from './sidenav.page.component';
|
||||
import { CallHistoryPageComponent } from './call-history.page.component';
|
||||
|
||||
export const COMPONENTS = [IndexPageComponent, SidenavPageComponent];
|
||||
export const COMPONENTS = [
|
||||
IndexPageComponent,
|
||||
SidenavPageComponent,
|
||||
CallHistoryPageComponent
|
||||
];
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
<div fxFlexFill>
|
||||
sidenav page of call is works!
|
||||
<div class="sidenav-container call" fxFlexFill fxLayout="column">
|
||||
<div class="title-section" fxFlex="0 0 50px" fxLayout="row">
|
||||
<div class="title">
|
||||
<h3 fxFlex="1 1 auto">{{ 'call:label.call' | ucapI18n }}</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="extra-box" fxFlex="0 0 50px">
|
||||
<app-organization-search-for-tenant
|
||||
[isBackspaceCanceled]="isBackspaceCanceled"
|
||||
[(searchData)]="companySearchData"
|
||||
(canceled)="onSearchCancel()"
|
||||
>
|
||||
</app-organization-search-for-tenant>
|
||||
</div>
|
||||
|
||||
<div fxFlex="1 1 auto">
|
||||
<app-sections-call-list
|
||||
[searchObj]="companySearchData"
|
||||
></app-sections-call-list>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
@import '~@ucap/lg-scss/mixins';
|
||||
|
||||
.sidenav-container.call {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
align-content: flex-start;
|
||||
background-color: #f1f2f6;
|
||||
|
||||
.title-section {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
background-color: $white;
|
||||
.title {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
justify-content: space-between;
|
||||
padding: 0 0 0 17px;
|
||||
background-color: $white;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
h3 {
|
||||
@include font-family-txt(18, left, $lipstick);
|
||||
align-items: center;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,13 +1,109 @@
|
|||
import { Component, Inject } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { Subject, combineLatest } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
|
||||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
OnDestroy,
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef
|
||||
} from '@angular/core';
|
||||
|
||||
import { Store, select } from '@ngrx/store';
|
||||
|
||||
import { User } from '@ucap/domain-organization';
|
||||
import { LoginSession, LoginInfo } from '@ucap/domain-authentication';
|
||||
import { SearchType, SearchDirectionByDateType } from '@ucap/domain-call';
|
||||
import { CallHistoryInfoRequest } from '@ucap/api-contact';
|
||||
|
||||
import { LogService } from '@ucap/ng-logger';
|
||||
import { CallActions } from '@ucap/ng-store-call';
|
||||
|
||||
import { UserSelector } from '@ucap/ng-store-organization';
|
||||
import { LoginSelector } from '@ucap/ng-store-authentication';
|
||||
|
||||
import { SearchData } from '@app/ucap/organization/models/search-data';
|
||||
import { AppAuthenticationService } from '@app/services/app-authentication.service';
|
||||
|
||||
import moment from 'moment';
|
||||
import { environment } from '@environments';
|
||||
|
||||
@Component({
|
||||
selector: 'app-pages-call-sidenav',
|
||||
templateUrl: './sidenav.page.component.html',
|
||||
styleUrls: ['./sidenav.page.component.scss']
|
||||
styleUrls: ['./sidenav.page.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class SidenavPageComponent {
|
||||
constructor(private logService: LogService) {}
|
||||
export class SidenavPageComponent implements OnInit, OnDestroy {
|
||||
set companySearchData(searchData: SearchData) {
|
||||
if (!!searchData && searchData.searchWord !== '') {
|
||||
this._companySearchData = { ...searchData, bySearch: true };
|
||||
} else {
|
||||
this._companySearchData = { ...searchData, bySearch: false };
|
||||
}
|
||||
}
|
||||
get companySearchData() {
|
||||
return this._companySearchData;
|
||||
}
|
||||
// tslint:disable-next-line: variable-name
|
||||
_companySearchData: SearchData;
|
||||
isBackspaceCanceled = true;
|
||||
|
||||
user: User;
|
||||
loginInfo: LoginInfo;
|
||||
loginSession: LoginSession;
|
||||
|
||||
private ngOnDestroySubject: Subject<void> = new Subject();
|
||||
constructor(
|
||||
private store: Store<any>,
|
||||
private appAuthenticationService: AppAuthenticationService,
|
||||
private changeDetectorRef: ChangeDetectorRef,
|
||||
private logService: LogService
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
combineLatest([
|
||||
this.store.pipe(select(UserSelector.user)),
|
||||
this.store.pipe(select(LoginSelector.loginInfo))
|
||||
])
|
||||
.pipe(takeUntil(this.ngOnDestroySubject))
|
||||
.subscribe(([user, loginInfo]) => {
|
||||
if (!!user && !!loginInfo) {
|
||||
this.user = user;
|
||||
this.loginInfo = loginInfo;
|
||||
this.loginSession = this.appAuthenticationService.getLoginSession();
|
||||
|
||||
this._retrieveCallHistory();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (!!this.ngOnDestroySubject) {
|
||||
this.ngOnDestroySubject.next();
|
||||
this.ngOnDestroySubject.complete();
|
||||
}
|
||||
}
|
||||
|
||||
onSearchCancel() {
|
||||
this.companySearchData = { ...this.companySearchData, searchWord: '' };
|
||||
}
|
||||
|
||||
private _retrieveCallHistory() {
|
||||
const searchStartDate = moment(new Date()).format('YYYY-MM-DD_HH:mm:ss');
|
||||
const req: CallHistoryInfoRequest = {
|
||||
userSeq: String(this.user.info.seq),
|
||||
deviceType: this.loginSession.deviceType,
|
||||
token: this.loginInfo.tokenString,
|
||||
searchType: SearchType.All,
|
||||
searchUserSeq: '',
|
||||
searchNumber: '',
|
||||
searchDate: '',
|
||||
searchStartDate,
|
||||
searchListCount:
|
||||
environment.productConfig.call.historyRequestDefaultCount,
|
||||
searchDirection: SearchDirectionByDateType.Before
|
||||
};
|
||||
this.store.dispatch(CallActions.callHistory({ req }));
|
||||
}
|
||||
}
|
||||
|
|
3
src/app/pages/call/types/params.type.ts
Normal file
3
src/app/pages/call/types/params.type.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
export enum QueryParams {
|
||||
ID = 'id'
|
||||
}
|
|
@ -14,7 +14,10 @@ import { AppChatSectionModule } from '@app/sections/chat/chat.section.module';
|
|||
|
||||
import { AppChatRoutingPageModule } from './chat-routing.page.module';
|
||||
|
||||
import { UiModule } from '@ucap/ng-ui';
|
||||
import { UiCoreModule } from '@ucap/ng-ui/core';
|
||||
import { UiDateModule } from '@ucap/ng-ui/date';
|
||||
import { UiViewerModule } from '@ucap/ng-ui/viewer';
|
||||
|
||||
import { COMPONENTS } from './components';
|
||||
import { UCAP_I18N_NAMESPACE, I18nModule } from '@ucap/ng-i18n';
|
||||
|
||||
|
@ -30,11 +33,14 @@ import { UCAP_I18N_NAMESPACE, I18nModule } from '@ucap/ng-i18n';
|
|||
MatSidenavModule,
|
||||
MatTooltipModule,
|
||||
|
||||
UiCoreModule,
|
||||
UiDateModule,
|
||||
UiViewerModule,
|
||||
|
||||
AppChatSectionModule,
|
||||
AppChatRoutingPageModule,
|
||||
|
||||
I18nModule,
|
||||
UiModule
|
||||
I18nModule
|
||||
],
|
||||
declarations: [...COMPONENTS],
|
||||
entryComponents: [],
|
||||
|
|
|
@ -8,12 +8,23 @@
|
|||
</div>
|
||||
<app-sections-chat-chat-search
|
||||
[isChatSearch]="isChatSearch"
|
||||
(chatSearch)="onChatSearch($event)"
|
||||
(closeChatSearch)="isChatSearch = false"
|
||||
></app-sections-chat-chat-search>
|
||||
<mat-drawer-container autosize fxFlex="1 1 auto" fxLayout="column">
|
||||
<div class="message-box-container" fxFlex="1 1 auto" fxLayout="column">
|
||||
<div
|
||||
class="message-box-container"
|
||||
fxFlex="1 1 auto"
|
||||
fxLayout="column"
|
||||
ucapFileUploadFor01
|
||||
(fileSelected)="onFileSelected($event)"
|
||||
(fileDragEnter)="onFileDragEnter($event)"
|
||||
(fileDragOver)="onFileDragOver($event)"
|
||||
(fileDragLeave)="onFileDragLeave($event)"
|
||||
>
|
||||
<div class="message-area" fxFlex="1 1 auto">
|
||||
<app-sections-chat-message
|
||||
#chatMessageSections
|
||||
[roomId]="roomId"
|
||||
[translationSimpleview]="translationSimpleview"
|
||||
[eventSendTrigger$]="eventSendTriggerSubject.asObservable()"
|
||||
|
@ -21,9 +32,11 @@
|
|||
</div>
|
||||
<div class="message-input" fxFlex="0 0 auto">
|
||||
<app-sections-chat-form
|
||||
#chatForm
|
||||
[roomId]="roomId"
|
||||
(changeTranslationSimpleview)="translationSimpleview = $event"
|
||||
(eventSendTrigger)="eventSendTriggerSubject.next($event)"
|
||||
(openFormSelector)="onOpenFormSelector()"
|
||||
></app-sections-chat-form>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,15 +1,25 @@
|
|||
import { Subject, BehaviorSubject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
|
||||
import { Component, ViewChild, OnInit, OnDestroy } from '@angular/core';
|
||||
import { ActivatedRoute, Params } from '@angular/router';
|
||||
|
||||
import { Store } from '@ngrx/store';
|
||||
|
||||
import { MatDrawer } from '@angular/material/sidenav';
|
||||
|
||||
import { Subscription, Subject, BehaviorSubject } from 'rxjs';
|
||||
import { ChattingActions } from '@ucap/ng-store-chat';
|
||||
|
||||
import { MessageSectionComponent } from '@app/sections/chat/components/message.section.component';
|
||||
import {
|
||||
FormSectionComponent,
|
||||
SelectorType
|
||||
} from '@app/sections/chat/components/form.section.component';
|
||||
|
||||
import { QueryParams } from '../types/params.type';
|
||||
import { ChatDrawType } from '../types/chat-draw.type';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { DrawInfo } from '../models/draw-info';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { RoomActions, ChattingActions } from '@ucap/ng-store-chat';
|
||||
import { SearchInfo } from '../models/search-info';
|
||||
|
||||
@Component({
|
||||
selector: 'app-pages-chat-room',
|
||||
|
@ -18,6 +28,11 @@ import { RoomActions, ChattingActions } from '@ucap/ng-store-chat';
|
|||
})
|
||||
export class ChatRoomPageComponent implements OnInit, OnDestroy {
|
||||
isChatSearch = false;
|
||||
searchObj: SearchInfo = {
|
||||
isShowSearch: false,
|
||||
searchWord: ''
|
||||
};
|
||||
|
||||
roomId: string;
|
||||
translationSimpleview = false;
|
||||
|
||||
|
@ -25,9 +40,15 @@ export class ChatRoomPageComponent implements OnInit, OnDestroy {
|
|||
returnDrawerType: ChatDrawType | null;
|
||||
eventSendTriggerSubject: BehaviorSubject<any> = new BehaviorSubject<any>(0);
|
||||
|
||||
@ViewChild('chatMessageSections', { static: false })
|
||||
chatMessageSections: MessageSectionComponent;
|
||||
|
||||
@ViewChild('chatRightDrawer', { static: false })
|
||||
chatRightDrawer: MatDrawer;
|
||||
|
||||
@ViewChild('chatForm', { static: false })
|
||||
chatForm: FormSectionComponent;
|
||||
|
||||
ChatDrawType = ChatDrawType;
|
||||
|
||||
private ngOnDestroySubject: Subject<void> = new Subject();
|
||||
|
@ -42,11 +63,20 @@ export class ChatRoomPageComponent implements OnInit, OnDestroy {
|
|||
.pipe(takeUntil(this.ngOnDestroySubject))
|
||||
.subscribe((params: Params) => {
|
||||
const seqParam = params[QueryParams.ROOM_ID];
|
||||
|
||||
// initializing by roomId Change.
|
||||
if (this.roomId !== seqParam) {
|
||||
// close Right Drawer.
|
||||
if (!!this.chatRightDrawer) {
|
||||
this.chatRightDrawer.close();
|
||||
}
|
||||
|
||||
// close Chat Search area.
|
||||
this.isChatSearch = false;
|
||||
this.searchObj = {
|
||||
isShowSearch: false,
|
||||
searchWord: ''
|
||||
};
|
||||
}
|
||||
|
||||
// setting roomId.
|
||||
|
@ -68,6 +98,14 @@ export class ChatRoomPageComponent implements OnInit, OnDestroy {
|
|||
this.store.dispatch(ChattingActions.clearActiveRoomId({}));
|
||||
}
|
||||
|
||||
/** About Form Selector */
|
||||
onOpenFormSelector() {
|
||||
if (!!this.chatMessageSections) {
|
||||
this.chatMessageSections.refreshAndScrollToBottom();
|
||||
}
|
||||
}
|
||||
|
||||
/** About Right drawer */
|
||||
onRightDrawerToggle(type: DrawInfo | null): void {
|
||||
this.drawerType = type.chatDrawType;
|
||||
this.returnDrawerType = !!type.returnDrawType ? type.returnDrawType : null;
|
||||
|
@ -78,4 +116,28 @@ export class ChatRoomPageComponent implements OnInit, OnDestroy {
|
|||
this.returnDrawerType = null;
|
||||
this.chatRightDrawer.close();
|
||||
}
|
||||
|
||||
/** About File Drag & Drop */
|
||||
onFileSelected(fileList: FileList) {
|
||||
if (!!this.chatForm) {
|
||||
this.chatForm.onDragAndDropFileupload(fileList); // direct upload
|
||||
// this.chatForm.onDragAndDropStandbyFileupload(fileList); // standby and confirm upload.(complate not yet)
|
||||
}
|
||||
}
|
||||
onFileDragEnter(event: DataTransferItemList) {
|
||||
// if (!!this.chatForm) {
|
||||
// this.chatForm.onOpenSelector(SelectorType.FILEUPLOAD);
|
||||
// }
|
||||
}
|
||||
onFileDragOver(event: DragEvent) {}
|
||||
onFileDragLeave(event: DragEvent) {
|
||||
// if (!!this.chatForm) {
|
||||
// this.chatForm.clearSelector();
|
||||
// }
|
||||
}
|
||||
|
||||
/** About Chat search. */
|
||||
onChatSearch(search: SearchInfo) {
|
||||
this.searchObj = search;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
@import '~@ucap/lg-scss/mixins';
|
||||
.index-page-chat-info {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
@ -18,4 +19,15 @@
|
|||
border-bottom: 1px solid #ccc;
|
||||
margin: 50px 0 0;
|
||||
}
|
||||
@include screen(xs) {
|
||||
.ico-page-chat {
|
||||
width: 120px;
|
||||
height: auto;
|
||||
margin-top: -40px;
|
||||
}
|
||||
.chat-index-copy {
|
||||
font-size: 1.2em;
|
||||
margin: 20px 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,10 +10,12 @@
|
|||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
justify-content: space-between;
|
||||
padding: 0 5px 0 17px;
|
||||
background-color: $white;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
min-height: 50px;
|
||||
padding: 0 5px 0 17px;
|
||||
background-color: $white;
|
||||
h3 {
|
||||
@include font-family-txt(18, left, $lipstick);
|
||||
align-items: center;
|
||||
|
|
|
@ -1,24 +1,32 @@
|
|||
import { Subject, of } from 'rxjs';
|
||||
import { takeUntil, take, map, catchError } from 'rxjs/operators';
|
||||
|
||||
import { Component, ChangeDetectorRef, OnInit, OnDestroy } from '@angular/core';
|
||||
import { ActivatedRoute, Params } from '@angular/router';
|
||||
|
||||
import { Store, select } from '@ngrx/store';
|
||||
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
|
||||
import { RoomInfo } from '@ucap/domain-chat';
|
||||
|
||||
import { ExitAllRequest } from '@ucap/protocol-room';
|
||||
|
||||
import { LogService } from '@ucap/ng-logger';
|
||||
import { Subject, of } from 'rxjs';
|
||||
import { Store, select } from '@ngrx/store';
|
||||
import { takeUntil, take, map, catchError } from 'rxjs/operators';
|
||||
import { I18nService } from '@ucap/ng-i18n';
|
||||
import { RoomSelector, RoomActions } from '@ucap/ng-store-chat';
|
||||
import { RoomInfo, ExitAllRequest } from '@ucap/protocol-room';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
|
||||
import {
|
||||
ConfirmDialogComponent,
|
||||
ConfirmDialogData,
|
||||
ConfirmDialogResult
|
||||
} from '@ucap/ng-ui';
|
||||
import { I18nService } from '@ucap/ng-i18n';
|
||||
import { SearchInfo } from '../models/search-info';
|
||||
import { ActivatedRoute, Params } from '@angular/router';
|
||||
import { QueryParams } from '../types/params.type';
|
||||
} from '@ucap/ng-ui/core';
|
||||
|
||||
import { AppChatService } from '@app/services/app-chat.service';
|
||||
import { SessionStorageService } from '@ucap/ng-web-storage';
|
||||
import { AppKey } from '@app/types';
|
||||
import { AppRoomSelector } from '@app/store/state';
|
||||
|
||||
import { SearchInfo } from '../models/search-info';
|
||||
import { QueryParams } from '../types/params.type';
|
||||
|
||||
@Component({
|
||||
selector: 'app-pages-chat-sidenav',
|
||||
|
@ -46,14 +54,18 @@ export class SidenavPageComponent implements OnInit, OnDestroy {
|
|||
private dialog: MatDialog,
|
||||
private i18nService: I18nService,
|
||||
private logService: LogService,
|
||||
private sessionStorageService: SessionStorageService,
|
||||
private activatedRoute: ActivatedRoute,
|
||||
private appChatService: AppChatService,
|
||||
private changeDetectorRef: ChangeDetectorRef
|
||||
) {
|
||||
this.historyRoomId = this.sessionStorageService.get<string>(
|
||||
AppKey.HistoryRoomId
|
||||
);
|
||||
this.store
|
||||
.pipe(
|
||||
takeUntil(this.ngOnDestroySubject),
|
||||
select(AppRoomSelector.historyRoomId)
|
||||
)
|
||||
.subscribe((historyRoomId) => {
|
||||
this.historyRoomId = historyRoomId;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
@ -62,10 +74,9 @@ export class SidenavPageComponent implements OnInit, OnDestroy {
|
|||
.subscribe((params: Params) => {
|
||||
const seqParam = params[QueryParams.ROOM_ID];
|
||||
|
||||
this.sessionStorageService.set<string>(
|
||||
AppKey.HistoryRoomId,
|
||||
!!seqParam ? seqParam : undefined
|
||||
);
|
||||
if (!!seqParam) {
|
||||
this.appChatService.setHistoryRoomId(seqParam);
|
||||
}
|
||||
|
||||
if (
|
||||
seqParam === undefined &&
|
||||
|
|
|
@ -22,7 +22,8 @@
|
|||
>
|
||||
<app-organization-profile-01
|
||||
[userSeq]="userSeq"
|
||||
(openChat)="onOpenCaht($event)"
|
||||
[companyList]="companyList"
|
||||
(openChat)="onOpenChat($event)"
|
||||
(sendMessage)="onSendMessage($event)"
|
||||
(sendCall)="onSendCall($event)"
|
||||
(sendSms)="onSendSms($event)"
|
||||
|
|
|
@ -48,9 +48,10 @@
|
|||
position: fixed;
|
||||
height: 49px;
|
||||
top: 40px;
|
||||
left: 75px;
|
||||
left: 60px;
|
||||
z-index: 10;
|
||||
width: calc(100% - 90px);
|
||||
width: calc(100% - 60px);
|
||||
background-color: rgba(255, 255, 255, 0.3);
|
||||
a {
|
||||
width: 50%;
|
||||
text-decoration: none;
|
||||
|
@ -66,11 +67,11 @@
|
|||
.profile-container {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
flex: 1 0 460px !important;
|
||||
flex: 0 0 460px !important;
|
||||
max-width: inherit !important;
|
||||
border-radius: 2px;
|
||||
@include screen(custom, min, 1540) {
|
||||
flex: 1 0 44% !important;
|
||||
flex: 0 0 44% !important;
|
||||
}
|
||||
@include screen(lg) {
|
||||
flex: 1 0 auto !important;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { takeUntil, take, map } from 'rxjs/operators';
|
||||
|
||||
import {
|
||||
Component,
|
||||
|
@ -14,22 +14,29 @@ import { MatDialog } from '@angular/material/dialog';
|
|||
|
||||
import { Store, select } from '@ngrx/store';
|
||||
|
||||
import { FileUploadItem } from '@ucap/api';
|
||||
import { FileUploadItem } from '@ucap/domain-common';
|
||||
import {
|
||||
UserInfoSS,
|
||||
UserInfoF,
|
||||
UserInfoUpdateType,
|
||||
User,
|
||||
Company
|
||||
} from '@ucap/domain-organization';
|
||||
|
||||
import { FileProfileSaveRequest } from '@ucap/api-common';
|
||||
import { VersionInfo2Response } from '@ucap/api-public';
|
||||
import { UserInfoSS, UserInfoF } from '@ucap/protocol-query';
|
||||
import { UserInfoUpdateType, User } from '@ucap/protocol-info';
|
||||
import { LoginResponse } from '@ucap/protocol-authentication';
|
||||
|
||||
import { ConferenceCreateRequest } from '@ucap/api-prompt';
|
||||
|
||||
import { LogService } from '@ucap/ng-logger';
|
||||
import { I18nService } from '@ucap/ng-i18n';
|
||||
import { UserSelector } from '@ucap/ng-store-organization';
|
||||
import { UserSelector, CompanySelector } from '@ucap/ng-store-organization';
|
||||
import { BuddySelector } from '@ucap/ng-store-group';
|
||||
import {
|
||||
LoginSelector,
|
||||
ConfigurationSelector
|
||||
} from '@ucap/ng-store-authentication';
|
||||
|
||||
import { UserInfoTypes } from '@app/types';
|
||||
import { UserInfoTypes, GroupManageType } from '@app/types';
|
||||
import { AppFileService } from '@app/services/app-file.service';
|
||||
import { AppAuthenticationService } from '@app/services/app-authentication.service';
|
||||
import { AppGroupService } from '@app/services/app-group.service';
|
||||
|
@ -37,6 +44,13 @@ import { AppGroupService } from '@app/services/app-group.service';
|
|||
import { QueryParams } from '../types/params.type';
|
||||
import { AppChatService } from '@app/services/app-chat.service';
|
||||
|
||||
import {
|
||||
EditUserDialogComponent,
|
||||
EditUserDialogData,
|
||||
EditUserDialogResult
|
||||
} from '@app/sections/group/dialogs/edit-user.dialog.component';
|
||||
import { LoginInfo, VersionInfo } from '@ucap/domain-authentication';
|
||||
|
||||
@Component({
|
||||
selector: 'app-pages-group-index',
|
||||
templateUrl: './index.page.component.html',
|
||||
|
@ -65,11 +79,13 @@ export class IndexPageComponent implements OnInit, OnDestroy {
|
|||
|
||||
userSeq: string = undefined;
|
||||
user: User;
|
||||
loginRes: LoginResponse;
|
||||
versionInfo2Res: VersionInfo2Response;
|
||||
loginInfo: LoginInfo;
|
||||
versionInfo: VersionInfo;
|
||||
activeLink = 0;
|
||||
tabName: string;
|
||||
profileName: string;
|
||||
buddyList: UserInfoTypes[];
|
||||
companyList: Company[];
|
||||
|
||||
ngOnInit(): void {
|
||||
this.activatedRoute.queryParams
|
||||
|
@ -91,18 +107,36 @@ export class IndexPageComponent implements OnInit, OnDestroy {
|
|||
this._refreshProfile();
|
||||
});
|
||||
this.store
|
||||
.pipe(takeUntil(this.ngOnDestroySubject), select(LoginSelector.loginRes))
|
||||
.subscribe((loginRes) => {
|
||||
this.loginRes = loginRes;
|
||||
.pipe(takeUntil(this.ngOnDestroySubject), select(LoginSelector.loginInfo))
|
||||
.subscribe((loginInfo) => {
|
||||
this.loginInfo = loginInfo;
|
||||
});
|
||||
|
||||
this.store
|
||||
.pipe(
|
||||
takeUntil(this.ngOnDestroySubject),
|
||||
select(ConfigurationSelector.versionInfo2Response)
|
||||
select(ConfigurationSelector.versionInfo)
|
||||
)
|
||||
.subscribe((versionInfo2Res) => {
|
||||
this.versionInfo2Res = versionInfo2Res;
|
||||
.subscribe((versionInfo) => {
|
||||
this.versionInfo = versionInfo;
|
||||
});
|
||||
|
||||
this.store
|
||||
.pipe(takeUntil(this.ngOnDestroySubject), select(BuddySelector.buddies))
|
||||
.subscribe((buddies) => {
|
||||
this.buddyList = buddies;
|
||||
});
|
||||
|
||||
this.store
|
||||
.pipe(
|
||||
takeUntil(this.ngOnDestroySubject),
|
||||
select(CompanySelector.companyList)
|
||||
)
|
||||
.subscribe((companyList) => {
|
||||
if (!companyList) {
|
||||
return;
|
||||
}
|
||||
this.companyList = companyList;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -113,7 +147,7 @@ export class IndexPageComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
}
|
||||
|
||||
onOpenCaht(userInfo: UserInfoSS) {
|
||||
onOpenChat(userInfo: UserInfoSS) {
|
||||
this.appChatService.newOpenRoom(
|
||||
[Number(userInfo.seq) as any],
|
||||
false,
|
||||
|
@ -123,29 +157,61 @@ export class IndexPageComponent implements OnInit, OnDestroy {
|
|||
onSendMessage(userInfo: UserInfoSS) {}
|
||||
onSendCall(call: string) {}
|
||||
onSendSms(employeeNum: string) {}
|
||||
onCreateConference(userSeq: number) {}
|
||||
onCreateConference(userSeq: number) {
|
||||
const loginSession = this.appAuthenticationService.getLoginSession();
|
||||
const req: ConferenceCreateRequest = {
|
||||
userSeq: String(this.user.info.seq),
|
||||
deviceType: loginSession.deviceType,
|
||||
tokenKey: this.loginInfo.tokenString,
|
||||
targetUserSeqs: [userSeq]
|
||||
};
|
||||
this.appChatService.openVideoConference(req);
|
||||
}
|
||||
onToggleFavorit(params: { userInfo: UserInfoSS; isFavorite: boolean }) {
|
||||
this.appGroupService.updateBuddy(params.userInfo, params.isFavorite);
|
||||
}
|
||||
onToggleBuddy(params: { userInfo: UserInfoSS; isBuddy: boolean }) {
|
||||
this.appGroupService
|
||||
.updateBuddyByToggle(params)
|
||||
.then((isRemoveBuddy) => {
|
||||
if (isRemoveBuddy) {
|
||||
this.router.navigate(
|
||||
[
|
||||
'group',
|
||||
{
|
||||
outlets: { content: 'index' }
|
||||
}
|
||||
],
|
||||
{
|
||||
queryParams: { id: Number(params.userInfo.seq) }
|
||||
}
|
||||
);
|
||||
if (params.isBuddy) {
|
||||
// 동료추가
|
||||
const dialogRef = this.dialog.open<
|
||||
EditUserDialogComponent,
|
||||
EditUserDialogData,
|
||||
EditUserDialogResult
|
||||
>(EditUserDialogComponent, {
|
||||
panelClass: 'max-create-dialog',
|
||||
data: {
|
||||
title: this.i18nService.t('group:dialog.title.addBuddy'),
|
||||
type: GroupManageType.Add,
|
||||
userInfos: [params.userInfo]
|
||||
}
|
||||
})
|
||||
.catch((reson) => this.logService.error(reson));
|
||||
});
|
||||
dialogRef
|
||||
.afterClosed()
|
||||
.pipe(
|
||||
take(1),
|
||||
map((result: EditUserDialogResult) => {
|
||||
if (!!result) {
|
||||
this.appGroupService.addBuddy(result);
|
||||
}
|
||||
})
|
||||
)
|
||||
.subscribe();
|
||||
} else {
|
||||
// 동료삭제
|
||||
this.appGroupService.removeBuddy(params.userInfo).then(() => {
|
||||
this.router.navigate(
|
||||
[
|
||||
'group',
|
||||
{
|
||||
outlets: { content: 'index' }
|
||||
}
|
||||
],
|
||||
{
|
||||
queryParams: { id: Number(params.userInfo.seq) }
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
onUploadProfileImage(profileImageFileUploadItem: FileUploadItem) {
|
||||
const loginSession = this.appAuthenticationService.getLoginSession();
|
||||
|
@ -153,14 +219,14 @@ export class IndexPageComponent implements OnInit, OnDestroy {
|
|||
const profile = {
|
||||
userSeq: String(this.user.info.seq),
|
||||
deviceType: loginSession.deviceType,
|
||||
token: this.loginRes.tokenString,
|
||||
token: this.loginInfo.tokenString,
|
||||
file: profileImageFileUploadItem.file,
|
||||
fileUploadItem: profileImageFileUploadItem
|
||||
} as FileProfileSaveRequest;
|
||||
|
||||
this.appFileServie.fileProfileSave(
|
||||
profile,
|
||||
this.versionInfo2Res.profileUploadUrl
|
||||
this.versionInfo.profileUploadUrl
|
||||
);
|
||||
}
|
||||
onUpdateIntro(intro: string) {
|
||||
|
@ -168,6 +234,15 @@ export class IndexPageComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
onUpdateNickname(params: { userInfo: UserInfoTypes; nickname: string }) {
|
||||
const isBuddy = this.appGroupService.checkBuddy(
|
||||
this.buddyList,
|
||||
params.userInfo
|
||||
);
|
||||
|
||||
if (!isBuddy) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.appGroupService.updateNickname(
|
||||
params.userInfo as UserInfoF,
|
||||
params.nickname
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
</div>
|
||||
<div class="extra-box" fxFlex="0 0 50px">
|
||||
<app-organization-search-for-tenant
|
||||
[isBackspaceCanceled]="isBackspaceCanceled"
|
||||
[(searchData)]="companySearchData"
|
||||
(canceled)="onSearchCancel()"
|
||||
>
|
||||
|
@ -34,6 +35,7 @@
|
|||
[searchData]="companySearchData"
|
||||
[showType]="showType"
|
||||
(clickUser)="onClickUser($event)"
|
||||
(openProfile)="onOpenProfile($event)"
|
||||
></app-sections-group-list>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { of, Subject } from 'rxjs';
|
||||
import { take, map, catchError } from 'rxjs/operators';
|
||||
import { take, map, catchError, takeUntil } from 'rxjs/operators';
|
||||
|
||||
import {
|
||||
Component,
|
||||
|
@ -7,7 +7,8 @@ import {
|
|||
OnDestroy,
|
||||
ChangeDetectorRef,
|
||||
ViewChild,
|
||||
ChangeDetectionStrategy
|
||||
ChangeDetectionStrategy,
|
||||
NgZone
|
||||
} from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
|
||||
|
@ -15,14 +16,19 @@ import { Store } from '@ngrx/store';
|
|||
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
|
||||
import { UserInfo } from '@ucap/domain-organization';
|
||||
|
||||
import { LogService } from '@ucap/ng-logger';
|
||||
import { I18nService } from '@ucap/ng-i18n';
|
||||
|
||||
import { SearchData } from '@app/ucap/organization/models/search-data';
|
||||
|
||||
import { LoginSession } from '@app/models/login-session';
|
||||
import { AppUiService } from '@app/services/app-ui.service';
|
||||
import { AppAuthenticationService } from '@app/services/app-authentication.service';
|
||||
import { CreateDialogComponent } from '@app/sections/group/dialogs/create.dialog.component';
|
||||
import { ListSectionComponent } from '@app/sections/group/components/list.section.component';
|
||||
import { UserInfo } from '@ucap/protocol-sync';
|
||||
|
||||
import { SortViewType } from '../types/sort-view.type';
|
||||
|
||||
@Component({
|
||||
|
@ -47,25 +53,43 @@ export class SidenavPageComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
// tslint:disable-next-line: variable-name
|
||||
_companySearchData: SearchData;
|
||||
|
||||
isBackspaceCanceled = true;
|
||||
showType: SortViewType;
|
||||
sortViewType = SortViewType;
|
||||
|
||||
private ngOnDestroySubject: Subject<void> = new Subject();
|
||||
|
||||
private loginSession: LoginSession;
|
||||
constructor(
|
||||
private activatedRoute: ActivatedRoute,
|
||||
private router: Router,
|
||||
private appAuthenticationService: AppAuthenticationService,
|
||||
private logService: LogService,
|
||||
private i18nService: I18nService,
|
||||
private store: Store<any>,
|
||||
private changeDetectorRef: ChangeDetectorRef,
|
||||
public dialog: MatDialog
|
||||
public dialog: MatDialog,
|
||||
private appUiService: AppUiService,
|
||||
private ngZone: NgZone
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.showType = SortViewType.all;
|
||||
this.showGroupMenuIcon(SortViewType.all);
|
||||
|
||||
this.appAuthenticationService
|
||||
.getLoginSession$()
|
||||
.pipe(takeUntil(this.ngOnDestroySubject))
|
||||
.subscribe((loginSession) => {
|
||||
this.loginSession = loginSession;
|
||||
if (
|
||||
!!this.loginSession &&
|
||||
!!this.loginSession.groupInfo &&
|
||||
!!this.loginSession.groupInfo.showType
|
||||
) {
|
||||
this.showType = this.loginSession.groupInfo.showType;
|
||||
this.showGroupMenuIcon(this.loginSession.groupInfo.showType);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
|
@ -132,6 +156,21 @@ export class SidenavPageComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (
|
||||
!!this.loginSession &&
|
||||
!!this.loginSession.groupInfo &&
|
||||
!!this.loginSession.groupInfo.showType
|
||||
) {
|
||||
this.appAuthenticationService.setLoginSession({
|
||||
...this.loginSession,
|
||||
groupInfo: {
|
||||
groupSeqs: [],
|
||||
lastGroupSeq: 0,
|
||||
showType: this.showType
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
onSearchCancel() {
|
||||
this.companySearchData = { ...this.companySearchData, searchWord: '' };
|
||||
|
@ -146,16 +185,24 @@ export class SidenavPageComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
onClickUser(userInfo: UserInfo) {
|
||||
this.router.navigate(
|
||||
[
|
||||
'group',
|
||||
this.ngZone.run(() => {
|
||||
this.router.navigate(
|
||||
[
|
||||
'group',
|
||||
{
|
||||
outlets: { content: 'index' }
|
||||
}
|
||||
],
|
||||
{
|
||||
outlets: { content: 'index' }
|
||||
queryParams: { id: Number(userInfo.seq) }
|
||||
}
|
||||
],
|
||||
{
|
||||
queryParams: { id: Number(userInfo.seq) }
|
||||
}
|
||||
);
|
||||
);
|
||||
|
||||
this.appUiService.closeLeftSidenavOnNarrowMode();
|
||||
});
|
||||
}
|
||||
|
||||
onOpenProfile(userInfo: UserInfo) {
|
||||
this.onClickUser(userInfo);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import { MatIconModule } from '@angular/material/icon';
|
|||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { MatTabsModule } from '@angular/material/tabs';
|
||||
|
||||
import { UiModule } from '@ucap/ng-ui';
|
||||
// import { UiModule } from '@ucap/ng-ui';
|
||||
|
||||
import { AppOrganizationModule } from '@app/ucap/organization/organization.module';
|
||||
|
||||
|
@ -34,7 +34,6 @@ import { I18nModule, UCAP_I18N_NAMESPACE } from '@ucap/ng-i18n';
|
|||
AppGroupSectionModule,
|
||||
AppGroupRoutingPageModule,
|
||||
|
||||
UiModule,
|
||||
I18nModule
|
||||
],
|
||||
declarations: [...COMPONENTS],
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
width: 200px;
|
||||
height: 200px;
|
||||
margin-top: -100px;
|
||||
background-image: url(../../../../assets/images/ico/img_coming_soon.png);
|
||||
background-image: url(/assets/images/ico/img_coming_soon.png);
|
||||
background-size: 100% auto;
|
||||
}
|
||||
.coming-soon-index-copy {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
<!-- search start-->
|
||||
<div fxFlex="0 0 50px">
|
||||
<app-organization-search-for-tenant
|
||||
[isBackspaceCanceled]="isBackspaceCanceled"
|
||||
[(searchData)]="companySearchData"
|
||||
(canceled)="onCanceledSearch()"
|
||||
>
|
||||
|
|
|
@ -12,11 +12,11 @@ import { ActivatedRoute, Router, Params } from '@angular/router';
|
|||
|
||||
import { ParamsUtil } from '@ucap/ng-core';
|
||||
|
||||
import { UserStore } from '@app/models/user-store';
|
||||
import { AppAuthenticationService } from '@app/services/app-authentication.service';
|
||||
import { SearchData } from '@app/ucap/organization/models/search-data';
|
||||
|
||||
import { QueryParams } from '../types/params.type';
|
||||
import { UserStore } from '@app/models/user-store';
|
||||
|
||||
@Component({
|
||||
selector: 'app-pages-organization-index',
|
||||
|
@ -36,7 +36,7 @@ export class IndexPageComponent implements OnInit, OnDestroy {
|
|||
_companySearchData: SearchData;
|
||||
|
||||
deptSearchData: SearchData;
|
||||
|
||||
isBackspaceCanceled = true;
|
||||
deptSeq: string;
|
||||
|
||||
private ngOnDestroySubject: Subject<void> = new Subject();
|
||||
|
@ -107,6 +107,7 @@ export class IndexPageComponent implements OnInit, OnDestroy {
|
|||
|
||||
onCanceledSearch() {
|
||||
const queryParams: Params = {};
|
||||
|
||||
queryParams[QueryParams.DEPT_SEQ] = String(this.deptSeq);
|
||||
this._navigate(queryParams);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
<div fxFlex="1 1 auto">
|
||||
<app-organization-tree
|
||||
[initialExpanded]="initialExpanded"
|
||||
[windowSizeMode]="windowSizeMode"
|
||||
(clicked)="onClickedTree($event)"
|
||||
></app-organization-tree>
|
||||
</div>
|
||||
|
|
|
@ -12,12 +12,17 @@ import { Router, ActivatedRoute, Params } from '@angular/router';
|
|||
|
||||
import { Store, select } from '@ngrx/store';
|
||||
|
||||
import { DeptInfo } from '@ucap/domain-organization';
|
||||
|
||||
import { LogService } from '@ucap/ng-logger';
|
||||
import { DeptInfo } from '@ucap/protocol-query';
|
||||
|
||||
import { DepartmentSelector, UserSelector } from '@ucap/ng-store-organization';
|
||||
import { LoginSelector } from '@ucap/ng-store-authentication';
|
||||
|
||||
import { AppUiService } from '@app/services/app-ui.service';
|
||||
import { AppSelector } from '@app/store/state';
|
||||
import { WindowSizeMode } from '@app/types/window-size-mode.type';
|
||||
|
||||
import { environment } from '@environments';
|
||||
|
||||
import { QueryParams } from '../types/params.type';
|
||||
|
@ -32,6 +37,7 @@ export class SidenavPageComponent implements OnInit, OnDestroy {
|
|||
initialExpanded: number;
|
||||
displayRoot = false;
|
||||
displayRootDept: DeptInfo;
|
||||
windowSizeMode: WindowSizeMode;
|
||||
|
||||
private ngOnDestroySubject: Subject<void> = new Subject();
|
||||
|
||||
|
@ -40,6 +46,7 @@ export class SidenavPageComponent implements OnInit, OnDestroy {
|
|||
private activatedRoute: ActivatedRoute,
|
||||
private store: Store<any>,
|
||||
private changeDetectorRef: ChangeDetectorRef,
|
||||
private appUiService: AppUiService,
|
||||
private logService: LogService
|
||||
) {
|
||||
this.logService.info('app-pages-ogranization-sidenav');
|
||||
|
@ -91,6 +98,15 @@ export class SidenavPageComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.store
|
||||
.pipe(
|
||||
takeUntil(this.ngOnDestroySubject),
|
||||
select(AppSelector.windowSizeMode)
|
||||
)
|
||||
.subscribe((windowSizeMode) => {
|
||||
this.windowSizeMode = windowSizeMode;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
|
@ -103,7 +119,6 @@ export class SidenavPageComponent implements OnInit, OnDestroy {
|
|||
onClickedTree(node: DeptInfo) {
|
||||
const queryParams: Params = {};
|
||||
queryParams[QueryParams.DEPT_SEQ] = String(node.seq);
|
||||
|
||||
this.router.navigate(
|
||||
[
|
||||
'organization',
|
||||
|
@ -115,5 +130,6 @@ export class SidenavPageComponent implements OnInit, OnDestroy {
|
|||
queryParams
|
||||
}
|
||||
);
|
||||
this.appUiService.closeLeftSidenavOnNarrowMode();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import { AppOrganizationRoutingPageModule } from './organization-routing.page.mo
|
|||
|
||||
import { COMPONENTS } from './components';
|
||||
import { I18nModule, UCAP_I18N_NAMESPACE } from '@ucap/ng-i18n';
|
||||
import { UiModule } from '@ucap/ng-ui';
|
||||
// import { UiModule } from '@ucap/ng-ui';
|
||||
import { OrganizationUiModule } from '@ucap/ng-ui-organization';
|
||||
|
||||
@NgModule({
|
||||
|
@ -30,8 +30,7 @@ import { OrganizationUiModule } from '@ucap/ng-ui-organization';
|
|||
AppOrganizationRoutingPageModule,
|
||||
|
||||
I18nModule,
|
||||
OrganizationUiModule,
|
||||
UiModule
|
||||
OrganizationUiModule
|
||||
],
|
||||
declarations: [...COMPONENTS],
|
||||
entryComponents: [],
|
||||
|
|
|
@ -101,13 +101,13 @@ export class AppSessionResolver implements Resolve<void> {
|
|||
|
||||
this.store.dispatch(
|
||||
ConfigurationActions.versionInfo2Success({
|
||||
res: versionInfo2Res
|
||||
versionInfo: versionInfo2Res.versionInfo
|
||||
})
|
||||
);
|
||||
|
||||
this.store.dispatch(
|
||||
ConfigurationActions.urlInfoSuccess({
|
||||
res: urlInfoRes
|
||||
urlInfo: urlInfoRes.urlInfo
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -128,7 +128,9 @@ export class AppSessionResolver implements Resolve<void> {
|
|||
}
|
||||
);
|
||||
|
||||
this.protocolService.connect(versionInfo2Res.serverIp);
|
||||
this.protocolService.connect(
|
||||
versionInfo2Res.versionInfo.serverIp
|
||||
);
|
||||
},
|
||||
(error) => {
|
||||
reject(error);
|
||||
|
|
|
@ -13,7 +13,7 @@ import { MatSelectModule } from '@angular/material/select';
|
|||
import { MatTabsModule } from '@angular/material/tabs';
|
||||
|
||||
import { I18nModule } from '@ucap/ng-i18n';
|
||||
import { UiModule } from '@ucap/ng-ui';
|
||||
// import { UiModule } from '@ucap/ng-ui';
|
||||
import { AuthenticationUiModule } from '@ucap/ng-ui-authentication';
|
||||
import { OrganizationUiModule } from '@ucap/ng-ui-organization';
|
||||
|
||||
|
@ -38,7 +38,6 @@ import { COMPONENTS } from './components';
|
|||
|
||||
I18nModule,
|
||||
|
||||
UiModule,
|
||||
AuthenticationUiModule,
|
||||
OrganizationUiModule,
|
||||
|
||||
|
|
63
src/app/sections/call/call.section.module.ts
Normal file
63
src/app/sections/call/call.section.module.ts
Normal file
|
@ -0,0 +1,63 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||
|
||||
import { ScrollingModule } from '@angular/cdk/scrolling';
|
||||
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { MatTabsModule } from '@angular/material/tabs';
|
||||
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
||||
|
||||
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
|
||||
|
||||
import { I18nModule, UCAP_I18N_NAMESPACE } from '@ucap/ng-i18n';
|
||||
// import { UiModule } from '@ucap/ng-ui';
|
||||
import { CallUiModule } from '@ucap/ng-ui-call';
|
||||
import { OrganizationUiModule } from '@ucap/ng-ui-organization';
|
||||
|
||||
import { AppLayoutsModule } from '@app/layouts/layouts.module';
|
||||
import { AppOrganizationModule } from '@app/ucap/organization/organization.module';
|
||||
import { AppGroupSectionModule } from '../group/group.section.module';
|
||||
|
||||
import { COMPONENTS } from './components';
|
||||
import { DIALOGS } from './dialogs';
|
||||
import { AppCallModule } from '@app/ucap/call/call.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
FlexLayoutModule,
|
||||
|
||||
MatIconModule,
|
||||
MatButtonModule,
|
||||
MatTooltipModule,
|
||||
MatTabsModule,
|
||||
MatProgressBarModule,
|
||||
|
||||
PerfectScrollbarModule,
|
||||
ScrollingModule,
|
||||
|
||||
I18nModule,
|
||||
|
||||
AppLayoutsModule,
|
||||
AppGroupSectionModule,
|
||||
AppOrganizationModule,
|
||||
AppCallModule,
|
||||
|
||||
CallUiModule,
|
||||
OrganizationUiModule
|
||||
],
|
||||
exports: [...COMPONENTS, ...DIALOGS],
|
||||
declarations: [...COMPONENTS, ...DIALOGS],
|
||||
entryComponents: [...DIALOGS],
|
||||
providers: [
|
||||
{
|
||||
provide: UCAP_I18N_NAMESPACE,
|
||||
useValue: ['call', 'common']
|
||||
}
|
||||
]
|
||||
})
|
||||
export class AppCallSectionModule {}
|
4
src/app/sections/call/components/index.ts
Normal file
4
src/app/sections/call/components/index.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
import { InfoSectionComponent } from './info.section.component';
|
||||
import { ListSectionComponent } from './list.section.component';
|
||||
|
||||
export const COMPONENTS = [InfoSectionComponent, ListSectionComponent];
|
28
src/app/sections/call/components/info.section.component.html
Normal file
28
src/app/sections/call/components/info.section.component.html
Normal file
|
@ -0,0 +1,28 @@
|
|||
<div class="app-sections-call-info-container" fxLayout="row">
|
||||
<div class="history-all" fxFlex="1 1 auto">
|
||||
<div class="subtitle2">{{ 'call:label.callHistory' | ucapI18n }}</div>
|
||||
<div class="list-container">
|
||||
<app-call-time-line
|
||||
[historyList]="originalHistoryList"
|
||||
></app-call-time-line>
|
||||
</div>
|
||||
</div>
|
||||
<div class="history-other" fxFlex="44%">
|
||||
<div class="history-away">
|
||||
<div class="subtitle2">{{ 'call:label.missed' | ucapI18n }}</div>
|
||||
<div class="list-container">
|
||||
<app-call-time-line
|
||||
[historyList]="awayHistoryList"
|
||||
></app-call-time-line>
|
||||
</div>
|
||||
</div>
|
||||
<div class="history-noreply">
|
||||
<div class="subtitle2">{{ 'call:label.unanswered' | ucapI18n }}</div>
|
||||
<div class="list-container">
|
||||
<app-call-time-line
|
||||
[historyList]="unansweredHistoryList"
|
||||
></app-call-time-line>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,32 @@
|
|||
import { TestBed, async } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { InfoSectionComponent } from './info.section.component';
|
||||
|
||||
describe('app::sections::group::InfoSectionComponent', () => {
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [RouterTestingModule],
|
||||
declarations: [InfoSectionComponent]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
it('should create the app', () => {
|
||||
const fixture = TestBed.createComponent(InfoSectionComponent);
|
||||
const app = fixture.componentInstance;
|
||||
expect(app).toBeTruthy();
|
||||
});
|
||||
|
||||
it(`should have as title 'ucap-lg-web'`, () => {
|
||||
const fixture = TestBed.createComponent(InfoSectionComponent);
|
||||
const app = fixture.componentInstance;
|
||||
});
|
||||
|
||||
it('should render title', () => {
|
||||
const fixture = TestBed.createComponent(InfoSectionComponent);
|
||||
fixture.detectChanges();
|
||||
const compiled = fixture.nativeElement;
|
||||
expect(compiled.querySelector('.content span').textContent).toContain(
|
||||
'ucap-lg-web app is running!'
|
||||
);
|
||||
});
|
||||
});
|
106
src/app/sections/call/components/info.section.component.ts
Normal file
106
src/app/sections/call/components/info.section.component.ts
Normal file
|
@ -0,0 +1,106 @@
|
|||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
OnDestroy,
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Input
|
||||
} from '@angular/core';
|
||||
import { Store, select } from '@ngrx/store';
|
||||
import { Subject, combineLatest } from 'rxjs';
|
||||
import { takeUntil, withLatestFrom } from 'rxjs/operators';
|
||||
import { CallSelector } from '@ucap/ng-store-call';
|
||||
import { CallHistory, CallResultType } from '@ucap/domain-call';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { UserSelector } from '@ucap/ng-store-organization';
|
||||
import { QueryParams } from '@app/pages/call/types/params.type';
|
||||
|
||||
@Component({
|
||||
selector: 'app-sections-call-info',
|
||||
templateUrl: './info.section.component.html',
|
||||
styleUrls: ['./info.section.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class InfoSectionComponent implements OnInit, OnDestroy {
|
||||
isMe: boolean;
|
||||
userSeq: string;
|
||||
|
||||
originalHistoryList: CallHistory[];
|
||||
awayHistoryList: CallHistory[];
|
||||
unansweredHistoryList: CallHistory[];
|
||||
|
||||
private ngOnDestroySubject: Subject<void> = new Subject();
|
||||
constructor(
|
||||
private store: Store<any>,
|
||||
private activatedRoute: ActivatedRoute,
|
||||
private changeDetectorRef: ChangeDetectorRef
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
combineLatest([
|
||||
this.activatedRoute.queryParams,
|
||||
this.store.pipe(select(CallSelector.callHistory))
|
||||
])
|
||||
.pipe(
|
||||
takeUntil(this.ngOnDestroySubject),
|
||||
withLatestFrom(this.store.pipe(select(UserSelector.user)))
|
||||
)
|
||||
.subscribe(([[params, callHistory], user]) => {
|
||||
let existParams = false;
|
||||
if (!!params) {
|
||||
const seqParam = params[QueryParams.ID];
|
||||
// initializing by userSeq Change.
|
||||
if (this.userSeq !== seqParam) {
|
||||
}
|
||||
// setting userSeq.
|
||||
this.userSeq = !!seqParam
|
||||
? seqParam
|
||||
: !!user
|
||||
? String(user.info.seq)
|
||||
: undefined;
|
||||
if (!!user && this.userSeq === String(user.info.seq)) {
|
||||
this.isMe = true;
|
||||
} else {
|
||||
this.isMe = false;
|
||||
}
|
||||
|
||||
this.originalHistoryList = callHistory;
|
||||
|
||||
this.getFiltered();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (!!this.ngOnDestroySubject) {
|
||||
this.ngOnDestroySubject.next();
|
||||
this.ngOnDestroySubject.complete();
|
||||
}
|
||||
}
|
||||
|
||||
getFiltered(): void {
|
||||
// original
|
||||
this.originalHistoryList = this.originalHistoryList.filter((item) => {
|
||||
let result = true;
|
||||
if (!this.isMe && !!this.userSeq) {
|
||||
if (!!item.sendYn && item.sendYn === true) {
|
||||
result = item.calledUserSeq === this.userSeq;
|
||||
} else {
|
||||
result = item.callingUserSeq === this.userSeq;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
});
|
||||
|
||||
// away
|
||||
this.awayHistoryList = this.originalHistoryList.filter(
|
||||
(item) => item.callResult === CallResultType.Away
|
||||
);
|
||||
// unanswered
|
||||
this.unansweredHistoryList = this.originalHistoryList.filter(
|
||||
(item) => item.callResult === CallResultType.Missed
|
||||
);
|
||||
|
||||
this.changeDetectorRef.markForCheck();
|
||||
}
|
||||
}
|
132
src/app/sections/call/components/list.section.component.html
Normal file
132
src/app/sections/call/components/list.section.component.html
Normal file
|
@ -0,0 +1,132 @@
|
|||
<div fxFlexFill class="list-container">
|
||||
<div class="select-call-section-content">
|
||||
<mat-tab-group
|
||||
#selectUserTabGroup
|
||||
mat-stretch-tabs
|
||||
class="tap-container tab_num2"
|
||||
>
|
||||
<mat-tab>
|
||||
<ng-template mat-tab-label>
|
||||
<p>
|
||||
<mat-icon>history</mat-icon>
|
||||
</p>
|
||||
</ng-template>
|
||||
<ng-template matTabContent>
|
||||
<div fxFlexFill class="select-tap">
|
||||
<div class="sub-title">
|
||||
{{ 'call:label.callHistory' | ucapI18n
|
||||
}}<strong>{{ filteredCallHistory.length }}</strong>
|
||||
</div>
|
||||
<div class="btns">
|
||||
<button
|
||||
mat-button
|
||||
[ngClass]="filteringByTypeClass(CallHistorySearchType.All)"
|
||||
(click)="filteringByType(CallHistorySearchType.All)"
|
||||
>
|
||||
{{ 'call:label.all' | ucapI18n }}
|
||||
</button>
|
||||
<button
|
||||
mat-button
|
||||
[ngClass]="filteringByTypeClass(CallHistorySearchType.Send)"
|
||||
(click)="filteringByType(CallHistorySearchType.Send)"
|
||||
>
|
||||
{{ 'call:label.send' | ucapI18n }}
|
||||
</button>
|
||||
<button
|
||||
mat-button
|
||||
[ngClass]="filteringByTypeClass(CallHistorySearchType.Receive)"
|
||||
(click)="filteringByType(CallHistorySearchType.Receive)"
|
||||
>
|
||||
{{ 'call:label.recieve' | ucapI18n }}
|
||||
</button>
|
||||
<button
|
||||
mat-button
|
||||
[ngClass]="filteringByTypeClass(CallHistorySearchType.Missed)"
|
||||
(click)="filteringByType(CallHistorySearchType.Missed)"
|
||||
>
|
||||
{{ 'call:label.missed' | ucapI18n }}
|
||||
</button>
|
||||
<button
|
||||
mat-button
|
||||
[ngClass]="
|
||||
filteringByTypeClass(CallHistorySearchType.UnAnswered)
|
||||
"
|
||||
(click)="filteringByType(CallHistorySearchType.UnAnswered)"
|
||||
>
|
||||
{{ 'call:label.unanswered' | ucapI18n }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="list">
|
||||
<app-call-history-expansion [itemList]="filteredCallHistory">
|
||||
</app-call-history-expansion>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</mat-tab>
|
||||
<mat-tab>
|
||||
<ng-template mat-tab-label>
|
||||
<p>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="21"
|
||||
height="19"
|
||||
viewBox="0 0 21 19"
|
||||
>
|
||||
<g
|
||||
id="icon_gnb_organiztion_g32"
|
||||
transform="translate(-12.917 -220.25)"
|
||||
>
|
||||
<g class="prefix__cls-1" transform="translate(19.917 220.25)">
|
||||
<circle cx="3.5" cy="3.5" r="3.5" class="prefix__cls-3" />
|
||||
<circle cx="3.5" cy="3.5" r="2.5" class="prefix__cls-4" />
|
||||
</g>
|
||||
<g class="prefix__cls-1" transform="translate(12.917 232.25)">
|
||||
<circle cx="3.5" cy="3.5" r="3.5" class="prefix__cls-3" />
|
||||
<circle cx="3.5" cy="3.5" r="2.5" class="prefix__cls-4" />
|
||||
</g>
|
||||
<g class="prefix__cls-1" transform="translate(19.917 232.25)">
|
||||
<circle cx="3.5" cy="3.5" r="3.5" class="prefix__cls-3" />
|
||||
<circle cx="3.5" cy="3.5" r="2.5" class="prefix__cls-4" />
|
||||
</g>
|
||||
<g class="prefix__cls-1" transform="translate(26.917 232.25)">
|
||||
<circle cx="3.5" cy="3.5" r="3.5" class="prefix__cls-3" />
|
||||
<circle cx="3.5" cy="3.5" r="2.5" class="prefix__cls-4" />
|
||||
</g>
|
||||
<path
|
||||
d="M16.5 233.312v-3.437h13.833v3.438"
|
||||
transform="translate(0 -1.087)"
|
||||
style="
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
stroke: #999;
|
||||
stroke-width: 2px;
|
||||
fill: none;
|
||||
"
|
||||
/>
|
||||
<path
|
||||
d="M0 0L0 6"
|
||||
class="prefix__cls-1"
|
||||
transform="translate(23.417 226.75)"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</p>
|
||||
</ng-template>
|
||||
<ng-template matTabContent>
|
||||
<div fxFlexFill class="select-tap">
|
||||
<div class="sub-title">
|
||||
{{ 'call:label.organization' | ucapI18n }}
|
||||
</div>
|
||||
<div class="list">
|
||||
<app-organization-profile-navigation-list
|
||||
[checkable]="false"
|
||||
[useFAB]="true"
|
||||
>
|
||||
</app-organization-profile-navigation-list>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,4 @@
|
|||
.list-container {
|
||||
height: calc(100% - 100px) !important;
|
||||
min-height: auto !important;
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
import { TestBed, async } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { ListSectionComponent } from './list.section.component';
|
||||
|
||||
describe('app::sections::group::ListSectionComponent', () => {
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [RouterTestingModule],
|
||||
declarations: [ListSectionComponent]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
it('should create the app', () => {
|
||||
const fixture = TestBed.createComponent(ListSectionComponent);
|
||||
const app = fixture.componentInstance;
|
||||
expect(app).toBeTruthy();
|
||||
});
|
||||
|
||||
it(`should have as title 'ucap-lg-web'`, () => {
|
||||
const fixture = TestBed.createComponent(ListSectionComponent);
|
||||
const app = fixture.componentInstance;
|
||||
});
|
||||
|
||||
it('should render title', () => {
|
||||
const fixture = TestBed.createComponent(ListSectionComponent);
|
||||
fixture.detectChanges();
|
||||
const compiled = fixture.nativeElement;
|
||||
expect(compiled.querySelector('.content span').textContent).toContain(
|
||||
'ucap-lg-web app is running!'
|
||||
);
|
||||
});
|
||||
});
|
114
src/app/sections/call/components/list.section.component.ts
Normal file
114
src/app/sections/call/components/list.section.component.ts
Normal file
|
@ -0,0 +1,114 @@
|
|||
import { Subject } from 'rxjs';
|
||||
|
||||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
OnDestroy,
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Input
|
||||
} from '@angular/core';
|
||||
|
||||
import { LogService } from '@ucap/ng-logger';
|
||||
|
||||
import { SearchData } from '@app/ucap/organization/models/search-data';
|
||||
import { Store, select } from '@ngrx/store';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { CallSelector } from '@ucap/ng-store-call';
|
||||
import {
|
||||
CallHistory,
|
||||
CallHistorySearchType,
|
||||
CallResultType
|
||||
} from '@ucap/domain-call';
|
||||
|
||||
@Component({
|
||||
selector: 'app-sections-call-list',
|
||||
templateUrl: './list.section.component.html',
|
||||
styleUrls: ['./list.section.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class ListSectionComponent implements OnInit, OnDestroy {
|
||||
@Input()
|
||||
set searchObj(obj: SearchData) {
|
||||
this._getFiltered();
|
||||
}
|
||||
get searchObj(): SearchData {
|
||||
return this._searchObj;
|
||||
}
|
||||
// tslint:disable-next-line: variable-name
|
||||
_searchObj: SearchData;
|
||||
|
||||
callHistory: CallHistory[];
|
||||
filteredCallHistory: CallHistory[];
|
||||
|
||||
searchType = CallHistorySearchType.All;
|
||||
CallHistorySearchType = CallHistorySearchType;
|
||||
|
||||
private ngOnDestroySubject: Subject<void> = new Subject();
|
||||
constructor(
|
||||
private store: Store<any>,
|
||||
private changeDetectorRef: ChangeDetectorRef,
|
||||
private logService: LogService
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.store
|
||||
.pipe(
|
||||
takeUntil(this.ngOnDestroySubject),
|
||||
select(CallSelector.callHistory)
|
||||
)
|
||||
.subscribe((callHistory) => {
|
||||
this.callHistory = callHistory;
|
||||
this._getFiltered();
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (!!this.ngOnDestroySubject) {
|
||||
this.ngOnDestroySubject.next();
|
||||
this.ngOnDestroySubject.complete();
|
||||
}
|
||||
}
|
||||
|
||||
filteringByTypeClass(searchType: CallHistorySearchType): string {
|
||||
return this.searchType === searchType ? 'cdk-active' : '';
|
||||
}
|
||||
filteringByType(searchType: CallHistorySearchType) {
|
||||
this.searchType = searchType;
|
||||
this._getFiltered();
|
||||
}
|
||||
|
||||
private _getFiltered() {
|
||||
if (!!this.callHistory && this.callHistory.length > 0) {
|
||||
switch (this.searchType) {
|
||||
case CallHistorySearchType.Send:
|
||||
this.filteredCallHistory = this.callHistory.filter(
|
||||
(item) => !!item.sendYn
|
||||
);
|
||||
break;
|
||||
case CallHistorySearchType.Receive:
|
||||
this.filteredCallHistory = this.callHistory.filter(
|
||||
(item) => !item.sendYn
|
||||
);
|
||||
break;
|
||||
case CallHistorySearchType.Missed:
|
||||
this.filteredCallHistory = this.callHistory.filter(
|
||||
(item) => item.callResult === CallResultType.Away
|
||||
);
|
||||
break;
|
||||
case CallHistorySearchType.UnAnswered:
|
||||
this.filteredCallHistory = this.callHistory.filter(
|
||||
(item) => item.callResult === CallResultType.Missed
|
||||
);
|
||||
break;
|
||||
default:
|
||||
// case CallHistorySearchType.All:
|
||||
this.filteredCallHistory = this.callHistory;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
this.filteredCallHistory = [];
|
||||
}
|
||||
this.changeDetectorRef.markForCheck();
|
||||
}
|
||||
}
|
14
src/app/sections/call/dialogs/dialpad.dialog.component.html
Normal file
14
src/app/sections/call/dialogs/dialpad.dialog.component.html
Normal file
|
@ -0,0 +1,14 @@
|
|||
<div class="dialog-container">
|
||||
<app-layouts-default-dialog
|
||||
[disableClose]="false"
|
||||
(closed)="onClosed($event)"
|
||||
class="ucap-dialog-call-dialpad-container"
|
||||
>
|
||||
<div appLayoutsDefaultDialog="header">
|
||||
{{ 'call:label.dialpad' | ucapI18n }}
|
||||
</div>
|
||||
<div class="dialog-body" appLayoutsDefaultDialog="body">
|
||||
<ucap-call-dialpad (sendCall)="onSendCall($event)"></ucap-call-dialpad>
|
||||
</div>
|
||||
</app-layouts-default-dialog>
|
||||
</div>
|
75
src/app/sections/call/dialogs/dialpad.dialog.component.scss
Normal file
75
src/app/sections/call/dialogs/dialpad.dialog.component.scss
Normal file
|
@ -0,0 +1,75 @@
|
|||
@import '~@ucap/lg-scss/mixins';
|
||||
.dialog-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.dialog-body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.profile {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding-bottom: 10px;
|
||||
margin-bottom: 10px;
|
||||
border-bottom: 1px solid #ccc;
|
||||
.profile-image {
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
margin-left: 0;
|
||||
background-color: #ffe8cb;
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
vertical-align: top;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
.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: 14px;
|
||||
font-weight: 600;
|
||||
order: 1;
|
||||
-ms-flex-order: 1;
|
||||
}
|
||||
.user-grade {
|
||||
@include ellipsis(1);
|
||||
align-self: stretch;
|
||||
font: {
|
||||
size: 13px;
|
||||
}
|
||||
margin-left: 4px;
|
||||
order: 0;
|
||||
-ms-flex-order: 0;
|
||||
}
|
||||
.write-date {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.contents {
|
||||
width: 100%;
|
||||
height: calc(100% - 60px);
|
||||
overflow: hidden;
|
||||
perfect-scrollbar {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding-right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { DebugElement } from '@angular/core';
|
||||
|
||||
import { TextDetailDialogComponent } from './text-detail.dialog.component';
|
||||
|
||||
describe('ucap::ui-organization::CreateChatDialogComponent', () => {
|
||||
let component: TextDetailDialogComponent;
|
||||
let fixture: ComponentFixture<TextDetailDialogComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [TextDetailDialogComponent]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(TextDetailDialogComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
86
src/app/sections/call/dialogs/dialpad.dialog.component.ts
Normal file
86
src/app/sections/call/dialogs/dialpad.dialog.component.ts
Normal file
|
@ -0,0 +1,86 @@
|
|||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
OnDestroy,
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Inject
|
||||
} from '@angular/core';
|
||||
|
||||
import {
|
||||
MatDialogRef,
|
||||
MAT_DIALOG_DATA,
|
||||
MatDialog
|
||||
} from '@angular/material/dialog';
|
||||
|
||||
import { Subject } from 'rxjs';
|
||||
import { Store, select } from '@ngrx/store';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
|
||||
import { User } from '@ucap/domain-organization';
|
||||
import { UserSelector } from '@ucap/ng-store-organization';
|
||||
import { LoginSelector } from '@ucap/ng-store-authentication';
|
||||
import { AppCallService } from '@app/services/app-call.service';
|
||||
import { AppAuthenticationService } from '@app/services/app-authentication.service';
|
||||
import { LoginSession, LoginInfo } from '@ucap/domain-authentication';
|
||||
|
||||
export interface DialpadDialogData {}
|
||||
export interface DialpadDialogResult {}
|
||||
|
||||
@Component({
|
||||
selector: 'app-dialog-call-dialpad',
|
||||
templateUrl: './dialpad.dialog.component.html',
|
||||
styleUrls: ['./dialpad.dialog.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class DialpadDialogComponent implements OnInit, OnDestroy {
|
||||
loginSession: LoginSession;
|
||||
loginInfo: LoginInfo;
|
||||
user: User;
|
||||
|
||||
private ngOnDestroySubject: Subject<void> = new Subject();
|
||||
constructor(
|
||||
private store: Store<any>,
|
||||
public dialogRef: MatDialogRef<DialpadDialogData, DialpadDialogResult>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: DialpadDialogData,
|
||||
private appCallService: AppCallService,
|
||||
private appAuthenticationService: AppAuthenticationService,
|
||||
private changeDetectorRef: ChangeDetectorRef
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.loginSession = this.appAuthenticationService.getLoginSession();
|
||||
this.store
|
||||
.pipe(takeUntil(this.ngOnDestroySubject), select(UserSelector.user))
|
||||
.subscribe((user) => {
|
||||
this.user = user;
|
||||
});
|
||||
|
||||
this.store
|
||||
.pipe(takeUntil(this.ngOnDestroySubject), select(LoginSelector.loginInfo))
|
||||
.subscribe((loginInfo) => {
|
||||
this.loginInfo = loginInfo;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (!!this.ngOnDestroySubject) {
|
||||
this.ngOnDestroySubject.next();
|
||||
this.ngOnDestroySubject.complete();
|
||||
}
|
||||
}
|
||||
|
||||
onSendCall(calleeNumber: string) {
|
||||
this.appCallService.sendClicktocall(
|
||||
this.loginInfo,
|
||||
this.user,
|
||||
this.loginSession.deviceType,
|
||||
calleeNumber
|
||||
);
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
||||
onClosed(event: MouseEvent): void {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
}
|
3
src/app/sections/call/dialogs/index.ts
Normal file
3
src/app/sections/call/dialogs/index.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
import { DialpadDialogComponent } from './dialpad.dialog.component';
|
||||
|
||||
export const DIALOGS = [DialpadDialogComponent];
|
|
@ -4,8 +4,6 @@ import { ReactiveFormsModule, FormsModule } from '@angular/forms';
|
|||
|
||||
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||
|
||||
import { ScrollingModule } from '@angular/cdk/scrolling';
|
||||
|
||||
import { MatRippleModule } from '@angular/material/core';
|
||||
import { MatAutocompleteModule } from '@angular/material/autocomplete';
|
||||
import { MatBadgeModule } from '@angular/material/badge';
|
||||
|
@ -30,7 +28,12 @@ import { MatProgressBarModule } from '@angular/material/progress-bar';
|
|||
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
|
||||
|
||||
import { I18nModule, UCAP_I18N_NAMESPACE } from '@ucap/ng-i18n';
|
||||
import { UiModule } from '@ucap/ng-ui';
|
||||
|
||||
import { UiCoreModule } from '@ucap/ng-ui/core';
|
||||
import { UiDateModule } from '@ucap/ng-ui/date';
|
||||
import { UiViewerModule } from '@ucap/ng-ui/viewer';
|
||||
import { UiscrollingModule } from '@ucap/ng-ui/scrolling';
|
||||
|
||||
import { ChatUiModule } from '@ucap/ng-ui-chat';
|
||||
import { OrganizationUiModule } from '@ucap/ng-ui-organization';
|
||||
import { AppOrganizationModule } from '@app/ucap/organization/organization.module';
|
||||
|
@ -42,6 +45,7 @@ import { AppGroupSectionModule } from '../group/group.section.module';
|
|||
import { COMPONENTS } from './components';
|
||||
import { DIALOGS } from './dialogs';
|
||||
import { DRAWERS } from './drawers';
|
||||
import { DIRECTIVES } from './directives';
|
||||
import { AppGroupModule } from '@app/ucap/group/group.module';
|
||||
|
||||
@NgModule({
|
||||
|
@ -73,10 +77,13 @@ import { AppGroupModule } from '@app/ucap/group/group.module';
|
|||
MatProgressBarModule,
|
||||
|
||||
PerfectScrollbarModule,
|
||||
ScrollingModule,
|
||||
|
||||
I18nModule,
|
||||
UiModule,
|
||||
|
||||
UiCoreModule,
|
||||
UiDateModule,
|
||||
UiViewerModule,
|
||||
UiscrollingModule,
|
||||
|
||||
AppLayoutsModule,
|
||||
AppGroupSectionModule,
|
||||
|
@ -87,8 +94,8 @@ import { AppGroupModule } from '@app/ucap/group/group.module';
|
|||
AppChatModule,
|
||||
AppGroupModule
|
||||
],
|
||||
exports: [...COMPONENTS, ...DIALOGS, ...DRAWERS],
|
||||
declarations: [...COMPONENTS, ...DIALOGS, ...DRAWERS],
|
||||
exports: [...COMPONENTS, ...DIALOGS, ...DRAWERS, ...DIRECTIVES],
|
||||
declarations: [...COMPONENTS, ...DIALOGS, ...DRAWERS, ...DIRECTIVES],
|
||||
entryComponents: [...DIALOGS, ...DRAWERS],
|
||||
providers: [
|
||||
{
|
||||
|
|
|
@ -3,15 +3,13 @@
|
|||
<app-chat-selector-sticker
|
||||
*ngSwitchCase="SelectorType.STICKER"
|
||||
(selectedSticker)="onSelectedSticker($event)"
|
||||
(closed)="selectorType = SelectorType.EMPTY"
|
||||
(closed)="clearSelector()"
|
||||
>
|
||||
</app-chat-selector-sticker>
|
||||
|
||||
<app-chat-selector-translation
|
||||
*ngSwitchCase="SelectorType.TRANSLATION"
|
||||
(closed)="
|
||||
selectorType = SelectorType.EMPTY; translationPreviewInfo = null
|
||||
"
|
||||
(closed)="clearSelector()"
|
||||
[destLocale]="destLocale"
|
||||
[simpleView]="translationSimpleview"
|
||||
[preView]="translationPreview"
|
||||
|
@ -26,18 +24,36 @@
|
|||
<app-chat-selector-file-upload
|
||||
#fileUploadSelector
|
||||
*ngSwitchCase="SelectorType.FILEUPLOAD"
|
||||
(closed)="selectorType = SelectorType.EMPTY"
|
||||
(closed)="clearSelector()"
|
||||
>
|
||||
</app-chat-selector-file-upload>
|
||||
|
||||
<app-chat-selector-email-send
|
||||
*ngSwitchCase="SelectorType.EMAILSENDER"
|
||||
(sendEventEmail)="onSendEventEmail($event)"
|
||||
(closed)="selectorType = SelectorType.EMPTY"
|
||||
(closed)="clearSelector()"
|
||||
></app-chat-selector-email-send>
|
||||
</ng-container>
|
||||
|
||||
<div class="chat-form-area ucap-mat-input-container">
|
||||
<!-- <div class="message-text" fxFlex floatLabel="never" appearance="none">
|
||||
<textarea
|
||||
#messageInput
|
||||
placeholder="{{ 'chat:label.inputChatMessage' | ucapI18n }}"
|
||||
name="message"
|
||||
(keydown)="textareaResize($event, messageInput)"
|
||||
(keydown.enter)="onKeydown($event)"
|
||||
></textarea>
|
||||
</div> -->
|
||||
<!-- <mat-form-field
|
||||
class="message-text"
|
||||
fxFlex
|
||||
floatLabel="never"
|
||||
appearance="none"
|
||||
>
|
||||
<mat-label>{{ 'chat:label.inputChatMessage' | ucapI18n }}</mat-label>
|
||||
<textarea matInput #messageInput></textarea>
|
||||
</mat-form-field> -->
|
||||
<mat-form-field
|
||||
class="message-text"
|
||||
fxFlex
|
||||
|
@ -45,19 +61,13 @@
|
|||
appearance="none"
|
||||
>
|
||||
<mat-label>{{ 'chat:label.inputChatMessage' | ucapI18n }}</mat-label>
|
||||
<!-- <textarea
|
||||
<textarea
|
||||
matInput
|
||||
#messageInput
|
||||
name="message"
|
||||
[matTextareaAutosize]="true"
|
||||
(keydown.enter)="onKeydown($event)"
|
||||
></textarea> -->
|
||||
<input
|
||||
matInput
|
||||
#messageInput
|
||||
name="message"
|
||||
(keydown.enter)="onKeydown($event)"
|
||||
/>
|
||||
></textarea>
|
||||
</mat-form-field>
|
||||
|
||||
<input
|
||||
|
@ -94,7 +104,7 @@
|
|||
</button>
|
||||
<!-- <button
|
||||
mat-icon-button
|
||||
*ngIf="!!authRes && !!authRes.useCapturePcScreen"
|
||||
*ngIf="!!userPermission && !!userPermission.useCapturePcScreen"
|
||||
aria-label="screenshot"
|
||||
matTooltipPosition="above"
|
||||
matTooltip="{{ 'label.screenshot' | ucapI18n }}"
|
||||
|
@ -115,7 +125,7 @@
|
|||
</button>
|
||||
<button
|
||||
mat-icon-button
|
||||
*ngIf="!!authRes && !!authRes.canSendEmail"
|
||||
*ngIf="!!userPermission && !!userPermission.canSendEmail"
|
||||
aria-label="emailSend"
|
||||
matTooltipPosition="above"
|
||||
matTooltip="{{ 'label.emailSend' | ucapI18n }}"
|
||||
|
@ -126,7 +136,7 @@
|
|||
</button>
|
||||
<button
|
||||
mat-icon-button
|
||||
*ngIf="!!authRes && !!authRes.canTranslation"
|
||||
*ngIf="!!userPermission && !!userPermission.canTranslation"
|
||||
aria-label="translation"
|
||||
matTooltipPosition="above"
|
||||
matTooltip="{{ 'label.translation' | ucapI18n }}"
|
||||
|
@ -137,7 +147,7 @@
|
|||
</button>
|
||||
<!-- <button
|
||||
mat-icon-button
|
||||
*ngIf="!!authRes && !!authRes.useGams"
|
||||
*ngIf="!!userPermission && !!userPermission.useGams"
|
||||
aria-label="gams"
|
||||
matTooltipPosition="above"
|
||||
matTooltip="{{ 'label.gams' | ucapI18n }}"
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
max-height: 100%;
|
||||
min-height: 20px;
|
||||
background-color: $white;
|
||||
padding-left: 30px;
|
||||
padding: 0 20px;
|
||||
font-size: 0.929em;
|
||||
margin: 8px 0;
|
||||
overflow-x: hidden;
|
||||
|
@ -19,9 +19,13 @@
|
|||
@include screen(xs) {
|
||||
padding-left: 16px;
|
||||
}
|
||||
textarea {
|
||||
min-height: 22px;
|
||||
overflow: hidden;
|
||||
.message-text {
|
||||
@include font-family($font-regular);
|
||||
textarea {
|
||||
min-height: 22px;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
.button-area {
|
||||
|
|
|
@ -18,28 +18,29 @@ import { Store, select } from '@ngrx/store';
|
|||
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
|
||||
import { FileUploadItem } from '@ucap/domain-common';
|
||||
import { User } from '@ucap/domain-organization';
|
||||
import { UserPermission } from '@ucap/domain-authorization';
|
||||
import {
|
||||
RoomInfo,
|
||||
EventType,
|
||||
MassTranslationEventJson,
|
||||
TranslationEventJson
|
||||
} from '@ucap/domain-chat';
|
||||
|
||||
import { StickerFilesInfo } from '@ucap/ng-core';
|
||||
import { StatusCode, FileUploadItem } from '@ucap/api';
|
||||
import { StatusCode } from '@ucap/api';
|
||||
import {
|
||||
TranslationSaveResponse,
|
||||
TranslationSaveRequest
|
||||
} from '@ucap/api-common';
|
||||
import { VersionInfo2Response } from '@ucap/api-public';
|
||||
|
||||
import {
|
||||
SendEventMailType,
|
||||
SendEventEmailRequest,
|
||||
SendEventEmailResponse,
|
||||
StatusCode as PiStatusCode
|
||||
} from '@ucap/pi';
|
||||
import { RoomInfo } from '@ucap/protocol-room';
|
||||
import {
|
||||
EventType,
|
||||
MassTranslationEventJson,
|
||||
TranslationEventJson
|
||||
} from '@ucap/protocol-event';
|
||||
import { LoginResponse } from '@ucap/protocol-authentication';
|
||||
import { AuthResponse } from '@ucap/protocol-query';
|
||||
import { User } from '@ucap/protocol-info';
|
||||
|
||||
import { I18nService } from '@ucap/ng-i18n';
|
||||
import { LogService } from '@ucap/ng-logger';
|
||||
|
@ -61,7 +62,7 @@ import {
|
|||
ConfirmDialogComponent,
|
||||
ConfirmDialogData,
|
||||
ConfirmDialogResult
|
||||
} from '@ucap/ng-ui';
|
||||
} from '@ucap/ng-ui/core';
|
||||
|
||||
import { LoginSession } from '@app/models/login-session';
|
||||
import { AppAuthenticationService } from '@app/services/app-authentication.service';
|
||||
|
@ -70,6 +71,7 @@ import { FileUploadSelectorComponent } from '@app/ucap/chat/components/file-uplo
|
|||
import { AppChatService } from '@app/services/app-chat.service';
|
||||
|
||||
import { environment } from '@environments';
|
||||
import { LoginInfo, VersionInfo } from '@ucap/domain-authentication';
|
||||
|
||||
export enum SelectorType {
|
||||
EMPTY = '',
|
||||
|
@ -107,14 +109,17 @@ export class FormSectionComponent implements OnInit, OnDestroy {
|
|||
@Output()
|
||||
changeTranslationSimpleview = new EventEmitter<boolean>();
|
||||
|
||||
@Output()
|
||||
openFormSelector = new EventEmitter<string>();
|
||||
|
||||
@Output()
|
||||
eventSendTrigger = new EventEmitter<any>();
|
||||
|
||||
versionInfo2Res: VersionInfo2Response;
|
||||
versionInfo: VersionInfo;
|
||||
loginSession: LoginSession;
|
||||
loginRes: LoginResponse;
|
||||
loginInfo: LoginInfo;
|
||||
user: User;
|
||||
authRes: AuthResponse;
|
||||
userPermission: UserPermission;
|
||||
|
||||
currentRoomInfo: RoomInfo;
|
||||
|
||||
|
@ -125,8 +130,8 @@ export class FormSectionComponent implements OnInit, OnDestroy {
|
|||
|
||||
/** About Translation */
|
||||
isTranslationProcess = false;
|
||||
translationSimpleview = true;
|
||||
translationPreview = true;
|
||||
translationSimpleview = false;
|
||||
translationPreview = false;
|
||||
destLocale = 'en'; // default English :: en
|
||||
translationPreviewInfo: {
|
||||
previewInfo: TranslationSaveResponse | null;
|
||||
|
@ -159,10 +164,10 @@ export class FormSectionComponent implements OnInit, OnDestroy {
|
|||
this.store
|
||||
.pipe(
|
||||
takeUntil(this.ngOnDestroySubject),
|
||||
select(ConfigurationSelector.versionInfo2Response)
|
||||
select(ConfigurationSelector.versionInfo)
|
||||
)
|
||||
.subscribe((versionInfo2Res) => {
|
||||
this.versionInfo2Res = versionInfo2Res;
|
||||
.subscribe((versionInfo) => {
|
||||
this.versionInfo = versionInfo;
|
||||
});
|
||||
|
||||
this.store
|
||||
|
@ -172,18 +177,18 @@ export class FormSectionComponent implements OnInit, OnDestroy {
|
|||
});
|
||||
|
||||
this.store
|
||||
.pipe(takeUntil(this.ngOnDestroySubject), select(LoginSelector.loginRes))
|
||||
.subscribe((loginRes) => {
|
||||
this.loginRes = loginRes;
|
||||
.pipe(takeUntil(this.ngOnDestroySubject), select(LoginSelector.loginInfo))
|
||||
.subscribe((loginInfo) => {
|
||||
this.loginInfo = loginInfo;
|
||||
});
|
||||
|
||||
this.store
|
||||
.pipe(
|
||||
takeUntil(this.ngOnDestroySubject),
|
||||
select(AuthorizationSelector.authResponse)
|
||||
select(AuthorizationSelector.userPermission)
|
||||
)
|
||||
.subscribe((authRes) => {
|
||||
this.authRes = authRes;
|
||||
.subscribe((userPermission) => {
|
||||
this.userPermission = userPermission;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -206,9 +211,10 @@ export class FormSectionComponent implements OnInit, OnDestroy {
|
|||
this.selectorType = SelectorType.EMPTY;
|
||||
this.translationSimpleview = false;
|
||||
this.changeTranslationSimpleview.emit(false);
|
||||
this.translationPreview = true;
|
||||
this.translationPreview = false;
|
||||
this.destLocale = 'en'; // default English :: en
|
||||
this.translationPreviewInfo = null;
|
||||
this.selectedSticker = undefined;
|
||||
|
||||
this.store
|
||||
.pipe(
|
||||
|
@ -225,11 +231,19 @@ export class FormSectionComponent implements OnInit, OnDestroy {
|
|||
/** About Selector */
|
||||
onOpenSelector(type: SelectorType): void {
|
||||
this.selectorType = type;
|
||||
this.changeDetectorRef.markForCheck();
|
||||
|
||||
this.selectedSticker = null;
|
||||
this.translationPreviewInfo = null;
|
||||
|
||||
this.changeDetectorRef.detectChanges();
|
||||
this.openFormSelector.emit(type);
|
||||
}
|
||||
clearSelector(): void {
|
||||
this.selectorType = SelectorType.EMPTY;
|
||||
|
||||
this.selectedSticker = null;
|
||||
this.translationPreviewInfo = null;
|
||||
|
||||
this.changeDetectorRef.markForCheck();
|
||||
}
|
||||
|
||||
|
@ -246,62 +260,6 @@ export class FormSectionComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
self.changeDetectorRef.detectChanges();
|
||||
|
||||
// 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.user,
|
||||
self.loginSession.deviceType,
|
||||
self.currentRoomInfo.roomId,
|
||||
fileUploadItems
|
||||
)
|
||||
.then((success) => {
|
||||
if (!!success) {
|
||||
self.clearSelector();
|
||||
if (!!self.fileUploadSelector) {
|
||||
self.fileUploadSelector.onUploadComplete();
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
self.clearSelector();
|
||||
if (!!self.fileUploadSelector) {
|
||||
self.fileUploadSelector.onUploadComplete();
|
||||
}
|
||||
|
||||
const msg = this.i18nService.t('common:file.errors.failToUpload');
|
||||
alert(msg);
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
self.fileInput.nativeElement.value = '';
|
||||
self.logService.error(`validUploadFile ${err}`);
|
||||
});
|
||||
}
|
||||
|
||||
onKeydown(event: KeyboardEvent) {
|
||||
// if (event.key === 'PageUp' || event.key === 'PageDown') {
|
||||
// event.preventDefault();
|
||||
|
@ -311,10 +269,17 @@ export class FormSectionComponent implements OnInit, OnDestroy {
|
|||
// this.send();
|
||||
// }
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.send();
|
||||
}
|
||||
|
||||
textareaResize(event: KeyboardEvent, obj) {
|
||||
const self = obj;
|
||||
setTimeout(() => {
|
||||
self.style.height = '1px';
|
||||
self.style.height = self.scrollHeight + 'px';
|
||||
});
|
||||
}
|
||||
|
||||
onSelectedSticker(stickerInfo: StickerFilesInfo) {
|
||||
this.selectedSticker = stickerInfo;
|
||||
this.focus(false);
|
||||
|
@ -412,7 +377,7 @@ export class FormSectionComponent implements OnInit, OnDestroy {
|
|||
) {
|
||||
/** CASE : MASS TEXT */
|
||||
this.appChatService.sendMessageOfMassText(
|
||||
this.loginRes,
|
||||
this.loginInfo,
|
||||
this.user,
|
||||
this.loginSession.deviceType,
|
||||
roomId,
|
||||
|
@ -437,7 +402,7 @@ export class FormSectionComponent implements OnInit, OnDestroy {
|
|||
this.commonApiService
|
||||
.translationSave({
|
||||
userSeq: String(this.user.info.seq),
|
||||
token: this.loginRes.tokenString,
|
||||
token: this.loginInfo.tokenString,
|
||||
deviceType: this.loginSession.deviceType,
|
||||
original: message,
|
||||
roomId: this.roomId,
|
||||
|
@ -547,6 +512,7 @@ export class FormSectionComponent implements OnInit, OnDestroy {
|
|||
sentMessage
|
||||
);
|
||||
this.translationPreviewInfo = undefined;
|
||||
this.eventSendTrigger.emit(0);
|
||||
this.focus();
|
||||
}
|
||||
|
||||
|
@ -580,7 +546,7 @@ export class FormSectionComponent implements OnInit, OnDestroy {
|
|||
const req: SendEventEmailRequest = {
|
||||
userSeq: String(this.user.info.seq),
|
||||
deviceType: this.loginSession.deviceType,
|
||||
tokenKey: this.loginRes.tokenString,
|
||||
tokenKey: this.loginInfo.tokenString,
|
||||
roomSeq: this._roomId,
|
||||
eventSeq: String(eventList[0].seq),
|
||||
sendType: type
|
||||
|
@ -624,4 +590,100 @@ export class FormSectionComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* About File Upload
|
||||
*/
|
||||
/** FileInput change event. */
|
||||
onChangeFileInput(): void {
|
||||
const fileList = this.fileInput.nativeElement.files;
|
||||
this._fileSend(fileList);
|
||||
}
|
||||
|
||||
/** DragAndDrop :: Add fileupload queue. not sending. */
|
||||
onDragAndDropStandbyFileupload(fileList: FileList) {
|
||||
const self = this;
|
||||
this.appFileService
|
||||
.validUploadFile(fileList, this.versionInfo?.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 = '';
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
self.fileInput.nativeElement.value = '';
|
||||
self.logService.error(`validUploadFile ${err}`);
|
||||
});
|
||||
}
|
||||
|
||||
/** DragAndDrop :: fileUpload direct. */
|
||||
onDragAndDropFileupload(fileList: FileList): void {
|
||||
this._fileSend(fileList);
|
||||
}
|
||||
|
||||
private _fileSend(fileList: FileList) {
|
||||
const self = this;
|
||||
this.appFileService
|
||||
.validUploadFile(fileList, this.versionInfo?.fileAllowSize)
|
||||
.then((result) => {
|
||||
if (!result) {
|
||||
self.fileInput.nativeElement.value = '';
|
||||
return;
|
||||
} else {
|
||||
// selector open
|
||||
self.onOpenSelector(SelectorType.FILEUPLOAD);
|
||||
self.changeDetectorRef.detectChanges();
|
||||
|
||||
// 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.loginInfo,
|
||||
self.user,
|
||||
self.loginSession.deviceType,
|
||||
self.currentRoomInfo.roomId,
|
||||
fileUploadItems
|
||||
)
|
||||
.then((success) => {
|
||||
if (!!success) {
|
||||
self.eventSendTrigger.emit(0);
|
||||
self.clearSelector();
|
||||
if (!!self.fileUploadSelector) {
|
||||
self.fileUploadSelector.onUploadComplete();
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
self.clearSelector();
|
||||
if (!!self.fileUploadSelector) {
|
||||
self.fileUploadSelector.onUploadComplete();
|
||||
}
|
||||
|
||||
const msg = this.i18nService.t('common:file.errors.failToUpload');
|
||||
alert(msg);
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
self.fileInput.nativeElement.value = '';
|
||||
self.logService.error(`validUploadFile ${err}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,19 @@
|
|||
<mat-toolbar class="info-chat-toolbar">
|
||||
<mat-toolbar-row class="info-chat-toolbar-content">
|
||||
<div class="chat-room-profile">
|
||||
<div class="profile-image">
|
||||
<div
|
||||
class="profile-image"
|
||||
(click)="onOpenProfile()"
|
||||
[style.cursor]="
|
||||
!!currentRoomInfo && currentRoomInfo.roomType === RoomType.Single
|
||||
? 'pointer'
|
||||
: 'default'
|
||||
"
|
||||
>
|
||||
<img
|
||||
class="thumbnail"
|
||||
ucapImage
|
||||
[base]="versionInfo2Res?.profileRoot"
|
||||
[base]="versionInfo?.profileRoot"
|
||||
[path]="roomImage"
|
||||
[default]="
|
||||
currentRoomInfo?.roomType === RoomType.Multi
|
||||
|
|
|
@ -13,15 +13,16 @@ import {
|
|||
} from '@angular/core';
|
||||
|
||||
import { Store, select } from '@ngrx/store';
|
||||
import { Dictionary } from '@ngrx/entity';
|
||||
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
|
||||
import { LocaleCode } from '@ucap/core';
|
||||
import { LocaleCode } from '@ucap/domain-common';
|
||||
import { User } from '@ucap/domain-organization';
|
||||
import { RoomInfo, RoomType } from '@ucap/domain-chat';
|
||||
|
||||
import { I18nService } from '@ucap/ng-i18n';
|
||||
import { VersionInfo2Response } from '@ucap/api-public';
|
||||
import { RoomInfo, RoomType, UpdateRequest } from '@ucap/protocol-room';
|
||||
import { User } from '@ucap/protocol-info';
|
||||
|
||||
import { UpdateRequest } from '@ucap/protocol-room';
|
||||
|
||||
import { UserSelector } from '@ucap/ng-store-organization';
|
||||
import { ConfigurationSelector } from '@ucap/ng-store-authentication';
|
||||
|
@ -40,6 +41,12 @@ import {
|
|||
import { AppChatService } from '@app/services/app-chat.service';
|
||||
import { ChatDrawType } from '@app/pages/chat/types/chat-draw.type';
|
||||
import { DrawInfo } from '@app/pages/chat/models/draw-info';
|
||||
import {
|
||||
ProfileDialogComponent,
|
||||
ProfileDialogData,
|
||||
ProfileDialogResult
|
||||
} from '@app/sections/organization/dialogs/profile.dialog.component';
|
||||
import { VersionInfo } from '@ucap/domain-authentication';
|
||||
|
||||
@Component({
|
||||
selector: 'app-sections-chat-info',
|
||||
|
@ -53,11 +60,13 @@ export class InfoSectionComponent implements OnInit, OnDestroy {
|
|||
|
||||
@Input()
|
||||
set roomId(roomId: string) {
|
||||
this._roomId = roomId;
|
||||
if (this._roomId !== roomId) {
|
||||
this._roomId = roomId;
|
||||
|
||||
this.roomIdSubject.next(roomId);
|
||||
this.roomIdSubject.next(roomId);
|
||||
|
||||
this.initializeRoomData();
|
||||
this.initializeRoomData();
|
||||
}
|
||||
|
||||
// request selected room
|
||||
if (!!this.roomId) {
|
||||
|
@ -81,7 +90,7 @@ export class InfoSectionComponent implements OnInit, OnDestroy {
|
|||
@Output()
|
||||
rightDrawerToggle = new EventEmitter<DrawInfo>();
|
||||
|
||||
versionInfo2Res: VersionInfo2Response;
|
||||
versionInfo: VersionInfo;
|
||||
user: User;
|
||||
|
||||
defaultProfileImage: string;
|
||||
|
@ -123,10 +132,10 @@ export class InfoSectionComponent implements OnInit, OnDestroy {
|
|||
this.store
|
||||
.pipe(
|
||||
takeUntil(this.ngOnDestroySubject),
|
||||
select(ConfigurationSelector.versionInfo2Response)
|
||||
select(ConfigurationSelector.versionInfo)
|
||||
)
|
||||
.subscribe((versionInfo2Res) => {
|
||||
this.versionInfo2Res = versionInfo2Res;
|
||||
.subscribe((versionInfo) => {
|
||||
this.versionInfo = versionInfo;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -240,6 +249,36 @@ export class InfoSectionComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
}
|
||||
|
||||
onOpenProfile(): void {
|
||||
if (
|
||||
!!this.currentRoomInfo &&
|
||||
this.currentRoomInfo.roomType === RoomType.Single
|
||||
) {
|
||||
const returnValue = this.appChatService.getRoomUserList01(
|
||||
this.user,
|
||||
this.roomUsersMap,
|
||||
this.roomUsersShortMap
|
||||
);
|
||||
if (
|
||||
!!returnValue &&
|
||||
!!returnValue.existUsers &&
|
||||
returnValue.users.length > 0
|
||||
) {
|
||||
const userSeq = String(returnValue.users[0].seq);
|
||||
this.dialog.open<
|
||||
ProfileDialogComponent,
|
||||
ProfileDialogData,
|
||||
ProfileDialogResult
|
||||
>(ProfileDialogComponent, {
|
||||
panelClass: 'mid-create-dialog',
|
||||
data: {
|
||||
userSeq
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getShowContextMenu(menuType: string) {
|
||||
if (
|
||||
['EVENT', 'ROOM_USERS', 'CHANGE_ROOM_USERS', 'ADD_GROUP', 'SETTING'].some(
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.list-container {
|
||||
height: calc(100% - 90px) !important;
|
||||
height: calc(100% - 100px) !important;
|
||||
min-height: auto !important;
|
||||
}
|
||||
|
|
|
@ -11,12 +11,15 @@ import {
|
|||
EventEmitter,
|
||||
Output
|
||||
} from '@angular/core';
|
||||
import { Router, ActivatedRoute, Params } from '@angular/router';
|
||||
|
||||
import { RoomInfo } from '@ucap/domain-chat';
|
||||
|
||||
import { LogService } from '@ucap/ng-logger';
|
||||
import { RoomInfo } from '@ucap/protocol-room';
|
||||
import { Router, ActivatedRoute, Params } from '@angular/router';
|
||||
|
||||
import { QueryParams } from '@app/pages/chat/types/params.type';
|
||||
import { SearchInfo } from '@app/pages/chat/models/search-info';
|
||||
import { AppChatService } from '@app/services/app-chat.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-sections-chat-list',
|
||||
|
@ -51,6 +54,7 @@ export class ListSectionComponent implements OnInit, OnDestroy {
|
|||
constructor(
|
||||
private router: Router,
|
||||
private activatedRoute: ActivatedRoute,
|
||||
private appChatService: AppChatService,
|
||||
private changeDetectorRef: ChangeDetectorRef,
|
||||
private logService: LogService
|
||||
) {}
|
||||
|
@ -76,17 +80,7 @@ export class ListSectionComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
onOpenChatRoom(roomInfo: RoomInfo): void {
|
||||
this.router.navigate(
|
||||
[
|
||||
'chat',
|
||||
{
|
||||
outlets: { content: 'chatroom' }
|
||||
}
|
||||
],
|
||||
{
|
||||
queryParams: { roomId: roomInfo.roomId }
|
||||
}
|
||||
);
|
||||
this.appChatService.openRoombyRoomId(roomInfo.roomId);
|
||||
}
|
||||
|
||||
onSearchResultList(searchResultList: RoomInfo[]) {
|
||||
|
|
|
@ -1,23 +1,36 @@
|
|||
<div #chatMessagesContainer class="ucap-message-section">
|
||||
<button
|
||||
mat-stroked-button
|
||||
color="accent"
|
||||
class="icon-button-arrow top-position"
|
||||
(click)="gotoScrollToBottom()"
|
||||
>
|
||||
<mat-icon>arrow_downward</mat-icon>
|
||||
</button>
|
||||
<!--대화창 위로 보내기
|
||||
<button
|
||||
mat-stroked-button
|
||||
color="accent"
|
||||
class="icon-button-arrow bottom-position"
|
||||
>
|
||||
<mat-icon>arrow_upward</mat-icon>
|
||||
</button>-->
|
||||
<!-- <div class="ucap-message-section"> -->
|
||||
<button
|
||||
mat-stroked-button
|
||||
color="accent"
|
||||
class="icon-button-arrow top-position"
|
||||
(click)="gotoScrollToBottom()"
|
||||
>
|
||||
<mat-icon>arrow_downward</mat-icon>
|
||||
</button>
|
||||
<!--대화창 위로 보내기
|
||||
<button
|
||||
mat-stroked-button
|
||||
color="accent"
|
||||
class="icon-button-arrow bottom-position"
|
||||
>
|
||||
<mat-icon>arrow_upward</mat-icon>
|
||||
</button>-->
|
||||
|
||||
<div #chatMessagesList class="chat-area">
|
||||
<div class="ucap-chat-more-event" *ngIf="!!currentChatting?.remainEvent">
|
||||
<ucap-virtual-scroll-viewport
|
||||
#vsList
|
||||
fxFlexFill
|
||||
class="ucap-message-section"
|
||||
perfectScrollbar
|
||||
measureSize
|
||||
minBufferPx="200"
|
||||
maxBufferPx="300"
|
||||
(contentSizeChanged)="onContentSizeChanged($event)"
|
||||
(measured)="onMeasured()"
|
||||
(psYReachEnd)="isScrollReachBottom = true; resetRecentMessage()"
|
||||
(psScrollUp)="isScrollReachBottom = false"
|
||||
>
|
||||
<ng-template ucapVirtualScrollHeader>
|
||||
<div class="ucap-chat-more-event" *ngIf="!!isRemainEvent">
|
||||
<button
|
||||
mat-button
|
||||
class="btn-more-pre bg-primary-chat"
|
||||
|
@ -28,31 +41,79 @@
|
|||
>{{ 'event.showPreviousEvents' | ucapI18n }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</ng-template>
|
||||
<div class="chat-area">
|
||||
<app-chat-message-box
|
||||
*ngFor="let event of eventList"
|
||||
*ucapVirtualFor="
|
||||
let event of eventList;
|
||||
keyOf: keyOf;
|
||||
templateCacheSize: 0
|
||||
"
|
||||
[message]="event"
|
||||
[roomInfo]="currentRoomInfo"
|
||||
[isMe]="event.senderSeq + '' === String(user?.info?.seq) + ''"
|
||||
[loginSession]="loginSession"
|
||||
[loginInfo]="loginInfo"
|
||||
[user]="user"
|
||||
[userPermission]="userPermission"
|
||||
[isMe]="String(user?.info?.seq) === String(event.senderSeq)"
|
||||
[translationSimpleview]="translationSimpleview"
|
||||
[senderInfo]="getSenderInfo(event.senderSeq)"
|
||||
[defaultProfileImage]="defaultProfileImage"
|
||||
[profileImageRoot]="versionInfo2Res?.profileRoot"
|
||||
[profileImageRoot]="versionInfo?.profileRoot"
|
||||
[dateChanged]="getDateSplitter(event)"
|
||||
[unreadCount]="getUnreadCount(event)"
|
||||
(messageContextMenu)="onClickMessageContextMenu($event)"
|
||||
(fileViewer)="onFileViewer($event)"
|
||||
(fileSave)="onFileSave($event)"
|
||||
(massTranslationDetail)="onMassTranslationDetail($event)"
|
||||
(openProfile)="onOpenProfile($event)"
|
||||
></app-chat-message-box>
|
||||
|
||||
<div *ngIf="false" class="recent-receive-message">
|
||||
<!-- 최근 메시지 영역 -->
|
||||
<app-chat-recent-message
|
||||
[senderInfo]="getSenderInfo(user?.info?.seq)"
|
||||
(joinConference)="onJoinConference($event)"
|
||||
>
|
||||
</app-chat-message-box>
|
||||
<!-- <app-chat-message-box
|
||||
*ngFor="let event of eventList; trackBy: trackByEvent"
|
||||
[message]="event"
|
||||
></app-chat-message-box> -->
|
||||
<!-- <app-chat-message-box
|
||||
*ngFor="let event of eventList; trackBy: trackByEvent"
|
||||
[message]="event"
|
||||
[roomInfo]="currentRoomInfo"
|
||||
[loginInfo]="loginInfo"
|
||||
[user]="user"
|
||||
[loginSession]="loginSession"
|
||||
[isMe]="String(user?.info?.seq) === String(event.senderSeq)"
|
||||
[translationSimpleview]="translationSimpleview"
|
||||
[senderInfo]="getSenderInfo(event.senderSeq)"
|
||||
[defaultProfileImage]="defaultProfileImage"
|
||||
[profileImageRoot]="versionInfo2Res?.profileRoot"
|
||||
[profileImageRoot]="versionInfo?.profileRoot"
|
||||
[dateChanged]="getDateSplitter(event)"
|
||||
[unreadCount]="getUnreadCount(event)"
|
||||
(messageContextMenu)="onClickMessageContextMenu($event)"
|
||||
(fileViewer)="onFileViewer($event)"
|
||||
(massTranslationDetail)="onMassTranslationDetail($event)"
|
||||
(openProfile)="onOpenProfile($event)"
|
||||
></app-chat-message-box> -->
|
||||
<!-- <p *ngFor="let event of eventList; trackBy: trackByEvent">
|
||||
{{ event.seq }} / {{ event.type }}
|
||||
</p> -->
|
||||
<!-- <div *ngIf="!!recentUserInfo" class="recent-receive-message">
|
||||
<app-chat-recent-message
|
||||
[senderInfo]="recentUserInfo"
|
||||
[message]="recentMessage"
|
||||
[defaultProfileImage]="defaultProfileImage"
|
||||
[profileImageRoot]="versionInfo?.profileRoot"
|
||||
(gotoBottom)="gotoScrollToBottom()"
|
||||
></app-chat-recent-message>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
</ucap-virtual-scroll-viewport>
|
||||
<div *ngIf="!!recentUserInfo" class="recent-receive-message">
|
||||
<app-chat-recent-message
|
||||
[senderInfo]="recentUserInfo"
|
||||
[message]="recentMessage"
|
||||
[defaultProfileImage]="defaultProfileImage"
|
||||
[profileImageRoot]="versionInfo?.profileRoot"
|
||||
(gotoBottom)="gotoScrollToBottom()"
|
||||
></app-chat-recent-message>
|
||||
</div>
|
||||
<!-- </div> -->
|
||||
|
|
|
@ -1,5 +1,30 @@
|
|||
@import '~@ucap/lg-scss/mixins';
|
||||
|
||||
.icon-button-arrow {
|
||||
@include ucapMatButton(36px, 36px, 6px, 36px);
|
||||
border-color: $lipstick;
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
box-shadow: 0 3px 6px 0 rgba(0, 0, 0, 0.16);
|
||||
// position: sticky;
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
z-index: 5;
|
||||
width: 36px;
|
||||
// align-self: flex-end;
|
||||
// margin-right: -10px;
|
||||
&.top-position {
|
||||
bottom: 90%;
|
||||
order: 2;
|
||||
}
|
||||
&.bottom-position {
|
||||
bottom: 30px;
|
||||
order: 3;
|
||||
}
|
||||
&:hover {
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
}
|
||||
|
||||
.ucap-message-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -11,54 +36,40 @@
|
|||
padding: 0 16px;
|
||||
min-width: 100%;
|
||||
}
|
||||
.icon-button-arrow {
|
||||
@include ucapMatButton(36px, 36px, 6px, 36px);
|
||||
border-color: $lipstick;
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
box-shadow: 0 3px 6px 0 rgba(0, 0, 0, 0.16);
|
||||
position: sticky;
|
||||
z-index: 5;
|
||||
width: 36px;
|
||||
align-self: flex-end;
|
||||
margin-right: -10px;
|
||||
&.top-position {
|
||||
bottom: 90%;
|
||||
order: 2;
|
||||
}
|
||||
&.bottom-position {
|
||||
bottom: 30px;
|
||||
order: 3;
|
||||
}
|
||||
&:hover {
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
|
||||
.ucap-chat-more-event {
|
||||
padding: 20px 30px 0;
|
||||
.btn-more-pre {
|
||||
@include ucapMatButton(100%, 30px, 2px, 30px);
|
||||
font-size: 0.857em;
|
||||
@include screen(xs) {
|
||||
padding: 0 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chat-area {
|
||||
flex-grow: 1;
|
||||
order: 1;
|
||||
padding-top: 30px;
|
||||
padding: 0 30px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.ucap-chat-more-event {
|
||||
padding: 20px 0 0;
|
||||
.btn-more-pre {
|
||||
@include ucapMatButton(100%, 30px, 2px, 30px);
|
||||
font-size: 0.857em;
|
||||
}
|
||||
}
|
||||
.recent-receive-message {
|
||||
transition: all 0.4s;
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 5;
|
||||
margin: 0 -30px;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
color: #fff;
|
||||
@include screen(xs) {
|
||||
margin: 0 -15px;
|
||||
}
|
||||
@include screen(xs) {
|
||||
padding: 0 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.recent-receive-message {
|
||||
transition: all 0.4s;
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 5;
|
||||
margin: 0 -30px;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
@include screen(xs) {
|
||||
margin: 0 -15px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,23 @@
|
|||
import moment from 'moment';
|
||||
|
||||
import { Subject, merge, combineLatest, Observable } from 'rxjs';
|
||||
import { takeUntil, take } from 'rxjs/operators';
|
||||
import {
|
||||
Subject,
|
||||
merge,
|
||||
combineLatest,
|
||||
Observable,
|
||||
fromEvent,
|
||||
interval
|
||||
} from 'rxjs';
|
||||
import {
|
||||
takeUntil,
|
||||
take,
|
||||
tap,
|
||||
withLatestFrom,
|
||||
debounce,
|
||||
debounceTime
|
||||
} from 'rxjs/operators';
|
||||
|
||||
import { PerfectScrollbarDirective } from 'ngx-perfect-scrollbar';
|
||||
|
||||
import {
|
||||
Component,
|
||||
|
@ -10,9 +26,9 @@ import {
|
|||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Input,
|
||||
AfterViewInit,
|
||||
ViewChild,
|
||||
ElementRef
|
||||
ElementRef,
|
||||
Inject
|
||||
} from '@angular/core';
|
||||
|
||||
import { Store, select } from '@ngrx/store';
|
||||
|
@ -20,53 +36,72 @@ import { Dictionary } from '@ngrx/entity';
|
|||
|
||||
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
|
||||
|
||||
import { TransMassTalkDownloadRequest } from '@ucap/api-common';
|
||||
import { VersionInfo2Response } from '@ucap/api-public';
|
||||
import { DeviceType, FileDownloadItem } from '@ucap/domain-common';
|
||||
import { User } from '@ucap/domain-organization';
|
||||
import {
|
||||
Info,
|
||||
EventJson,
|
||||
EventType,
|
||||
FileType,
|
||||
MassTranslationEventJson
|
||||
} from '@ucap/protocol-event';
|
||||
import {
|
||||
MassTranslationEventJson,
|
||||
FileEventJson,
|
||||
UserInfo as RoomUserInfo,
|
||||
UserInfoShort as RoomUserInfoShort,
|
||||
RoomInfo,
|
||||
UpdateTimerSetRequest,
|
||||
UpdateRequest,
|
||||
RoomType
|
||||
} from '@ucap/protocol-room';
|
||||
import { LoginResponse } from '@ucap/protocol-authentication';
|
||||
import { FileInfo } from '@ucap/protocol-file';
|
||||
import { User } from '@ucap/protocol-info';
|
||||
RoomType,
|
||||
FileInfo
|
||||
} from '@ucap/domain-chat';
|
||||
|
||||
import { TransMassTalkDownloadRequest } from '@ucap/api-common';
|
||||
|
||||
import {
|
||||
ReadRequest,
|
||||
SSVC_TYPE_EVENT_SEND_NOTI,
|
||||
SendNotification
|
||||
} from '@ucap/protocol-event';
|
||||
import { UpdateTimerSetRequest, UpdateRequest } from '@ucap/protocol-room';
|
||||
|
||||
import { NativeService } from '@ucap/native';
|
||||
|
||||
import { I18nService } from '@ucap/ng-i18n';
|
||||
|
||||
import { UserSelector } from '@ucap/ng-store-organization';
|
||||
import {
|
||||
LoginSelector,
|
||||
ConfigurationSelector
|
||||
ConfigurationSelector,
|
||||
AuthorizationSelector
|
||||
} from '@ucap/ng-store-authentication';
|
||||
import {
|
||||
ChattingSelector,
|
||||
RoomSelector,
|
||||
ChattingActions,
|
||||
RoomActions,
|
||||
Chatting
|
||||
ChatUtil
|
||||
} from '@ucap/ng-store-chat';
|
||||
|
||||
import {
|
||||
ConfirmDialogComponent,
|
||||
ConfirmDialogData,
|
||||
ConfirmDialogResult,
|
||||
ClipboardService,
|
||||
SelectFileInfo
|
||||
} from '@ucap/ng-ui';
|
||||
AlertDialogComponent,
|
||||
AlertDialogData,
|
||||
AlertDialogResult,
|
||||
ClipboardService
|
||||
} from '@ucap/ng-ui/core';
|
||||
import { SelectFileInfo } from '@ucap/ng-ui/viewer';
|
||||
import {
|
||||
VirtualScrollViewportComponent,
|
||||
MeasureSizeVirtualScrollDirective
|
||||
} from '@ucap/ng-ui/scrolling';
|
||||
|
||||
import { EventProtocolService } from '@ucap/ng-protocol-event';
|
||||
import { UCAP_NATIVE_SERVICE } from '@ucap/ng-native';
|
||||
import { LogService } from '@ucap/ng-logger';
|
||||
|
||||
import { LoginSession } from '@app/models/login-session';
|
||||
import { AppChatService } from '@app/services/app-chat.service';
|
||||
import { AppAuthenticationService } from '@app/services/app-authentication.service';
|
||||
import { AppOrganizationService } from '@app/services/app-organization.service';
|
||||
import { AppFileService } from '@app/services/app-file.service';
|
||||
|
||||
import {
|
||||
ProfileDialogComponent,
|
||||
ProfileDialogData,
|
||||
|
@ -78,16 +113,15 @@ import {
|
|||
ForwardDialogData,
|
||||
ForwardDialogResult
|
||||
} from '../dialogs/forward.dialog.component';
|
||||
import {
|
||||
FileViewerDialogComponent,
|
||||
FileViewerDialogData,
|
||||
FileViewerDialogResult
|
||||
} from '../dialogs/file-viewer.dialog.component';
|
||||
import { FileViewerDialogData } from '../dialogs/file-viewer.dialog.component';
|
||||
import {
|
||||
SettingDialogComponent,
|
||||
SettingDialogData,
|
||||
SettingDialogResult
|
||||
} from '../dialogs/setting.dialog.component';
|
||||
import { ConferenceJoinRequest } from '@ucap/api-prompt';
|
||||
import { LoginInfo, VersionInfo } from '@ucap/domain-authentication';
|
||||
import { UserPermission } from '@ucap/domain-authorization';
|
||||
|
||||
@Component({
|
||||
selector: 'app-sections-chat-message',
|
||||
|
@ -96,18 +130,19 @@ import {
|
|||
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class MessageSectionComponent
|
||||
implements OnInit, OnDestroy, AfterViewInit {
|
||||
export class MessageSectionComponent implements OnInit, OnDestroy {
|
||||
private roomIdSubject = new Subject<string>();
|
||||
private ngOnDestroySubject: Subject<void> = new Subject();
|
||||
|
||||
@Input()
|
||||
set roomId(roomId: string) {
|
||||
this._roomId = roomId;
|
||||
if (this._roomId !== roomId) {
|
||||
this._roomId = roomId;
|
||||
|
||||
this.roomIdSubject.next(roomId);
|
||||
this.roomIdSubject.next(roomId);
|
||||
|
||||
this.initializeRoomData();
|
||||
this.initializeRoomData();
|
||||
}
|
||||
}
|
||||
get roomId(): string {
|
||||
return this._roomId;
|
||||
|
@ -121,13 +156,14 @@ export class MessageSectionComponent
|
|||
@Input()
|
||||
eventSendTrigger$: Observable<any>;
|
||||
|
||||
versionInfo2Res: VersionInfo2Response;
|
||||
loginRes: LoginResponse;
|
||||
versionInfo: VersionInfo;
|
||||
loginInfo: LoginInfo;
|
||||
user: User;
|
||||
loginSession: LoginSession;
|
||||
userPermission: UserPermission;
|
||||
|
||||
currentRoomInfo: RoomInfo;
|
||||
currentChatting: Chatting;
|
||||
isRemainEvent = false;
|
||||
currentFileInfoList: FileInfo[] = [];
|
||||
roomUsers: RoomUserInfoShort[] = [];
|
||||
// eventList$: Observable<Info<EventJson>[]>;
|
||||
|
@ -137,6 +173,10 @@ export class MessageSectionComponent
|
|||
EventType = EventType;
|
||||
FileType = FileType;
|
||||
|
||||
/** 최근 메시지 */
|
||||
recentMessage: Info<EventJson>;
|
||||
recentUserInfo: RoomUserInfoShort | RoomUserInfo | undefined;
|
||||
|
||||
/** Timer 대화방의 대화 삭제를 위한 interval */
|
||||
interval: any;
|
||||
|
||||
|
@ -145,9 +185,25 @@ export class MessageSectionComponent
|
|||
|
||||
/** About Scroll */
|
||||
isInitScrollbottom = true;
|
||||
@ViewChild('chatMessagesContainer', { static: false })
|
||||
isScrollReachBottom = false;
|
||||
@ViewChild('chatMessagesContainer', { static: true })
|
||||
chatMessagesContainer: ElementRef<HTMLElement>;
|
||||
|
||||
@ViewChild('vsList', { static: false })
|
||||
vsList: VirtualScrollViewportComponent;
|
||||
|
||||
@ViewChild('vsList', {
|
||||
static: true,
|
||||
read: MeasureSizeVirtualScrollDirective
|
||||
})
|
||||
measureSize: MeasureSizeVirtualScrollDirective;
|
||||
|
||||
@ViewChild(PerfectScrollbarDirective, {
|
||||
static: true,
|
||||
read: PerfectScrollbarDirective
|
||||
})
|
||||
psDirectiveRef: PerfectScrollbarDirective;
|
||||
|
||||
String = String;
|
||||
|
||||
constructor(
|
||||
|
@ -156,32 +212,109 @@ export class MessageSectionComponent
|
|||
private changeDetectorRef: ChangeDetectorRef,
|
||||
private dialog: MatDialog,
|
||||
private i18nService: I18nService,
|
||||
private appAuthenticationService: AppAuthenticationService
|
||||
private eventProtocolService: EventProtocolService,
|
||||
private appAuthenticationService: AppAuthenticationService,
|
||||
private appOrganizationService: AppOrganizationService,
|
||||
private appFileService: AppFileService,
|
||||
@Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService,
|
||||
private logService: LogService
|
||||
) {
|
||||
this.defaultProfileImage = this.appChatService.defaultProfileImage;
|
||||
|
||||
// scroll handling when window size changing.
|
||||
fromEvent(window, 'resize')
|
||||
.pipe(takeUntil(this.ngOnDestroySubject), debounceTime(300))
|
||||
.subscribe((event: any) => {
|
||||
this.refreshAndScrollToBottom();
|
||||
});
|
||||
|
||||
this.eventProtocolService.notification$
|
||||
.pipe(
|
||||
takeUntil(this.ngOnDestroySubject),
|
||||
withLatestFrom(this.store.pipe(select(RoomSelector.rooms))),
|
||||
tap(([notiOrRes, roomList]) => {
|
||||
switch (notiOrRes.SSVC_TYPE) {
|
||||
case SSVC_TYPE_EVENT_SEND_NOTI:
|
||||
{
|
||||
const noti = notiOrRes as SendNotification;
|
||||
const roomId = noti.roomId;
|
||||
const eventInfo = noti.info;
|
||||
const trgtRoom = roomList.find(
|
||||
(roomInfo) => roomInfo.roomId === roomId
|
||||
);
|
||||
|
||||
const contents = ChatUtil.convertFinalEventMessage(
|
||||
noti.eventType,
|
||||
noti.info.sentMessageJson
|
||||
);
|
||||
|
||||
this.logService.debug(
|
||||
'Notification::eventProtocolService::SendNotification in message.section.components',
|
||||
noti
|
||||
);
|
||||
|
||||
if (!!roomId && roomId === this.roomId) {
|
||||
if (!!this.isScrollReachBottom) {
|
||||
// Fires when I enter the event
|
||||
this.isInitScrollbottom = true;
|
||||
} else {
|
||||
this.recentMessage = noti.info;
|
||||
this.recentUserInfo = this.getSenderInfo(
|
||||
Number(noti.SENDER_SEQ)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// ignore..
|
||||
break;
|
||||
}
|
||||
})
|
||||
)
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.vsList
|
||||
.elementScrolled()
|
||||
.pipe(takeUntil(this.ngOnDestroySubject))
|
||||
.subscribe(() => {
|
||||
if (!!this.psDirectiveRef) {
|
||||
this.psDirectiveRef.update();
|
||||
}
|
||||
});
|
||||
|
||||
this.store
|
||||
.pipe(
|
||||
takeUntil(this.ngOnDestroySubject),
|
||||
select(ConfigurationSelector.versionInfo2Response)
|
||||
select(AuthorizationSelector.userPermission)
|
||||
)
|
||||
.subscribe((versionInfo2Res) => (this.versionInfo2Res = versionInfo2Res));
|
||||
|
||||
this.store
|
||||
.pipe(takeUntil(this.ngOnDestroySubject), select(LoginSelector.loginRes))
|
||||
.subscribe((loginRes) => (this.loginRes = loginRes));
|
||||
|
||||
this.store
|
||||
.pipe(takeUntil(this.ngOnDestroySubject), select(UserSelector.user))
|
||||
.subscribe((user) => (this.user = user));
|
||||
.subscribe((userPermission) => {
|
||||
this.userPermission = userPermission;
|
||||
});
|
||||
|
||||
this.eventSendTrigger$
|
||||
.pipe(takeUntil(this.ngOnDestroySubject))
|
||||
.subscribe((_) => {
|
||||
// Fires when I enter the event
|
||||
this.gotoScrollToBottom();
|
||||
this.isInitScrollbottom = true;
|
||||
});
|
||||
|
||||
this.nativeService
|
||||
.window_onFocus$()
|
||||
.pipe(takeUntil(this.ngOnDestroySubject))
|
||||
.subscribe((isFocus) => {
|
||||
if (!!this.roomId && !!this.eventList && this.eventList.length > 0) {
|
||||
const roomId = this.roomId;
|
||||
const lastReadSeq = this.eventList[this.eventList.length - 1].seq;
|
||||
this.store.dispatch(
|
||||
ChattingActions.read({
|
||||
roomId,
|
||||
lastReadSeq
|
||||
} as ReadRequest)
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -202,35 +335,21 @@ export class MessageSectionComponent
|
|||
}
|
||||
}
|
||||
|
||||
ngAfterViewInit() {}
|
||||
|
||||
initializeRoomData() {
|
||||
/** About initialize roomId */
|
||||
this.isInitScrollbottom = true;
|
||||
this.onClickInvalidateCache();
|
||||
|
||||
this.loginSession = this.appAuthenticationService.getLoginSession();
|
||||
|
||||
this.store
|
||||
.pipe(
|
||||
takeUntil(merge(this.ngOnDestroySubject, this.roomIdSubject)),
|
||||
select(RoomSelector.room, this.roomId)
|
||||
)
|
||||
.subscribe((room) => {
|
||||
this.currentRoomInfo = room;
|
||||
|
||||
// About Interval
|
||||
if (!!this.interval) {
|
||||
clearInterval(this.interval);
|
||||
this.interval = undefined;
|
||||
}
|
||||
if (!!this.currentRoomInfo && !!this.currentRoomInfo.isTimeRoom) {
|
||||
this.interval = setInterval(() => {
|
||||
this.store.dispatch(
|
||||
ChattingActions.intervalClearEvent({ roomId: this.roomId })
|
||||
);
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
.pipe(take(1), select(ConfigurationSelector.versionInfo))
|
||||
.subscribe((versionInfo) => (this.versionInfo = versionInfo));
|
||||
this.store
|
||||
.pipe(take(1), select(LoginSelector.loginInfo))
|
||||
.subscribe((loginInfo) => (this.loginInfo = loginInfo));
|
||||
this.store
|
||||
.pipe(take(1), select(UserSelector.user))
|
||||
.subscribe((user) => (this.user = user));
|
||||
|
||||
this.store
|
||||
.pipe(
|
||||
|
@ -250,7 +369,12 @@ export class MessageSectionComponent
|
|||
select(ChattingSelector.chatting, this.roomId)
|
||||
)
|
||||
.subscribe((chatting) => {
|
||||
this.currentChatting = chatting;
|
||||
if (!!chatting && !!chatting.remainEvent) {
|
||||
this.isRemainEvent = chatting.remainEvent;
|
||||
} else {
|
||||
this.isRemainEvent = false;
|
||||
}
|
||||
|
||||
if (
|
||||
!!chatting &&
|
||||
!!chatting.fileInfoList &&
|
||||
|
@ -285,12 +409,6 @@ export class MessageSectionComponent
|
|||
.subscribe((eventList) => {
|
||||
if (!!eventList && eventList.length > 0) {
|
||||
this.eventList = eventList;
|
||||
this.changeDetectorRef.markForCheck();
|
||||
|
||||
if (!!this.isInitScrollbottom) {
|
||||
this.gotoScrollToBottom();
|
||||
this.isInitScrollbottom = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -301,11 +419,46 @@ export class MessageSectionComponent
|
|||
])
|
||||
.pipe(takeUntil(merge(this.ngOnDestroySubject, this.roomIdSubject)))
|
||||
.subscribe(([roomInfo, standbyRooms]) => {
|
||||
// get room info.
|
||||
if (!!roomInfo) {
|
||||
if (
|
||||
!!this.currentRoomInfo &&
|
||||
this.currentRoomInfo.roomId === roomInfo.roomId
|
||||
) {
|
||||
this.currentRoomInfo = {
|
||||
...this.currentRoomInfo,
|
||||
roomName: roomInfo.roomName,
|
||||
joinUserCount: roomInfo.joinUserCount,
|
||||
isJoinRoom: roomInfo.isJoinRoom,
|
||||
expiredFileStdSeq: roomInfo.expiredFileStdSeq,
|
||||
timeRoomInterval: roomInfo.timeRoomInterval
|
||||
};
|
||||
} else {
|
||||
// all refresh
|
||||
this.currentRoomInfo = roomInfo;
|
||||
}
|
||||
|
||||
// About Interval
|
||||
if (!!this.interval) {
|
||||
clearInterval(this.interval);
|
||||
this.interval = undefined;
|
||||
}
|
||||
if (!!this.currentRoomInfo && !!this.currentRoomInfo.isTimeRoom) {
|
||||
this.interval = setInterval(() => {
|
||||
this.store.dispatch(
|
||||
ChattingActions.intervalClearEvent({ roomId: this.roomId })
|
||||
);
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
// new room setting popup
|
||||
if (
|
||||
!!roomInfo &&
|
||||
roomInfo.roomId === this.roomId &&
|
||||
roomInfo.roomType !== RoomType.Mytalk &&
|
||||
roomInfo.roomType !== RoomType.Single &&
|
||||
(roomInfo.roomType !== RoomType.Single ||
|
||||
(roomInfo.roomType === RoomType.Single && !!roomInfo.isTimeRoom)) &&
|
||||
!!standbyRooms &&
|
||||
standbyRooms.length > 0 &&
|
||||
standbyRooms.findIndex((roomId) => roomId === this.roomId) > -1
|
||||
|
@ -337,13 +490,57 @@ export class MessageSectionComponent
|
|||
});
|
||||
}
|
||||
|
||||
/** About scrolling */
|
||||
keyOf = (item: Info<EventJson>): string | number => {
|
||||
return item.seq;
|
||||
};
|
||||
|
||||
onMeasured() {
|
||||
if (!!this.isInitScrollbottom) {
|
||||
this.gotoScrollToBottom();
|
||||
this.isInitScrollbottom = false;
|
||||
}
|
||||
}
|
||||
|
||||
onContentSizeChanged(size: number) {
|
||||
if (!!this.psDirectiveRef) {
|
||||
this.psDirectiveRef.update();
|
||||
}
|
||||
}
|
||||
|
||||
onClickScrollTo(i: string) {
|
||||
const index = Number(i);
|
||||
// const offset = this.vsList.offsetForIndex(index, 'start');
|
||||
// this.psDirectiveRef.scrollToY(offset);
|
||||
// console.log('offset', offset, this.psDirectiveRef.ps().element.scrollTop);
|
||||
|
||||
this.vsList.scrollToIndex(index, 'center');
|
||||
}
|
||||
|
||||
onClickInvalidateCache() {
|
||||
if (!!this.measureSize) {
|
||||
this.measureSize.invalidateMeasurements();
|
||||
}
|
||||
}
|
||||
|
||||
gotoScrollToBottom() {
|
||||
if (!!this.chatMessagesContainer) {
|
||||
const self = this;
|
||||
setTimeout(() => {
|
||||
self.chatMessagesContainer.nativeElement.scrollTop =
|
||||
self.chatMessagesContainer.nativeElement.scrollHeight;
|
||||
}, 500);
|
||||
// recent message reset;
|
||||
this.resetRecentMessage();
|
||||
|
||||
// scrolling.
|
||||
if (!!this.vsList && !!this.eventList && this.eventList.length > 0) {
|
||||
this.vsList.scrollToIndex(this.eventList.length - 1, 'end');
|
||||
}
|
||||
}
|
||||
|
||||
refreshAndScrollToBottom() {
|
||||
// if (!!this.vsList && !!this.isScrollReachBottom) {
|
||||
// this.isInitScrollbottom = false;
|
||||
// this.vsList.checkViewportSize();
|
||||
// }
|
||||
if (!!this.psDirectiveRef && !!this.isScrollReachBottom) {
|
||||
this.psDirectiveRef.update();
|
||||
this.psDirectiveRef.scrollToBottom();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -353,7 +550,7 @@ export class MessageSectionComponent
|
|||
): RoomUserInfoShort | RoomUserInfo | undefined {
|
||||
if (!!this.roomUsers && this.roomUsers.length) {
|
||||
return this.roomUsers.find(
|
||||
(userInfo) => userInfo.seq + '' === senderSeq + ''
|
||||
(userInfo) => String(senderSeq) === String(userInfo.seq)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -366,8 +563,7 @@ export class MessageSectionComponent
|
|||
|
||||
if (curIndex === 0) {
|
||||
return true;
|
||||
}
|
||||
if (curIndex > 0) {
|
||||
} else if (curIndex > 0) {
|
||||
if (!this.eventList[curIndex]) {
|
||||
return false;
|
||||
}
|
||||
|
@ -376,16 +572,18 @@ export class MessageSectionComponent
|
|||
'day'
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Unread Count calculation */
|
||||
getUnreadCount(message: Info<EventJson>): string | number {
|
||||
const unreadCnt = this.roomUsers
|
||||
.filter(
|
||||
(user) => user.isJoinRoom && user.seq + '' !== message.senderSeq + ''
|
||||
)
|
||||
.filter((user) => user.lastReadEventSeq < message.seq).length;
|
||||
const unreadCnt = this.roomUsers.filter(
|
||||
(user) =>
|
||||
user.isJoinRoom &&
|
||||
String(message.senderSeq) !== String(user.seq) &&
|
||||
user.lastReadEventSeq < message.seq
|
||||
).length;
|
||||
return unreadCnt === 0 ? '' : unreadCnt;
|
||||
}
|
||||
|
||||
|
@ -393,7 +591,7 @@ export class MessageSectionComponent
|
|||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
if (!!this.currentChatting.remainEvent) {
|
||||
if (!!this.isRemainEvent) {
|
||||
this.store.dispatch(
|
||||
ChattingActions.moreEvents({
|
||||
roomId: this.roomId
|
||||
|
@ -422,7 +620,7 @@ export class MessageSectionComponent
|
|||
this.appChatService.massTextDownload({
|
||||
userSeq: String(this.user.info.seq),
|
||||
deviceType: this.loginSession.deviceType,
|
||||
token: this.loginRes.tokenString,
|
||||
token: this.loginInfo.tokenString,
|
||||
eventMassSeq: params.message.seq
|
||||
});
|
||||
}
|
||||
|
@ -525,7 +723,7 @@ export class MessageSectionComponent
|
|||
break;
|
||||
case 'FORWARD_TO_ME':
|
||||
{
|
||||
if (this.loginRes.talkWithMeBotSeq > -1) {
|
||||
if (this.loginInfo.talkWithMeBotSeq > -1) {
|
||||
const seqs = this.user.talkWithMeBotSeq as any;
|
||||
this.store.dispatch(
|
||||
ChattingActions.forward({
|
||||
|
@ -580,7 +778,7 @@ export class MessageSectionComponent
|
|||
}) {
|
||||
const req = {
|
||||
userSeq: String(this.user.info.seq),
|
||||
token: this.loginRes.tokenString,
|
||||
token: this.loginInfo.tokenString,
|
||||
deviceType: this.loginSession.deviceType,
|
||||
eventTransSeq: params.message.sentMessageJson.translationSeq.toString()
|
||||
} as TransMassTalkDownloadRequest;
|
||||
|
@ -592,16 +790,133 @@ export class MessageSectionComponent
|
|||
);
|
||||
}
|
||||
|
||||
onFileViewer(selectFileInfo: SelectFileInfo) {
|
||||
const data: FileViewerDialogData = {
|
||||
fileInfos: this.currentFileInfoList,
|
||||
selectFileInfo,
|
||||
downloadUrl: this.versionInfo2Res.downloadUrl,
|
||||
deviceType: this.loginSession.deviceType,
|
||||
token: this.loginRes.tokenString,
|
||||
userSeq: String(this.user.info.seq)
|
||||
};
|
||||
this.appChatService.openFileviwer(data);
|
||||
onFileViewer(params: {
|
||||
selectFileInfo: SelectFileInfo;
|
||||
senderInfo: RoomUserInfoShort | RoomUserInfo;
|
||||
}) {
|
||||
const self = this;
|
||||
this.appOrganizationService
|
||||
.getUserInfo({ userSeq: String(params.senderInfo.seq), user: this.user })
|
||||
.then((result) => {
|
||||
let isValid = false;
|
||||
if (
|
||||
!!result &&
|
||||
!!result.userInfo &&
|
||||
!!self.userPermission &&
|
||||
self.userPermission.fileTransferAllowedCompanyList.indexOf(
|
||||
result.userInfo.companyCode
|
||||
) > -1
|
||||
) {
|
||||
isValid = true;
|
||||
}
|
||||
|
||||
if (!!isValid) {
|
||||
const data: FileViewerDialogData = {
|
||||
fileInfos: self.currentFileInfoList,
|
||||
selectFileInfo: params.selectFileInfo,
|
||||
downloadUrl: self.versionInfo.downloadUrl,
|
||||
deviceType: self.loginSession.deviceType,
|
||||
token: self.loginInfo.tokenString,
|
||||
userSeq: String(self.user.info.seq)
|
||||
};
|
||||
self.appChatService.openFileviwer(data);
|
||||
} else {
|
||||
self._openAlert(
|
||||
self.i18nService.t('common:file.errors.disapprovalCompany')
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch((reason) => {
|
||||
self._openAlert(
|
||||
self.i18nService.t('common:file.errors.disapprovalCompany')
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
onFileSave(params: {
|
||||
fileInfo: FileEventJson;
|
||||
fileDownloadItem: FileDownloadItem;
|
||||
type: string;
|
||||
senderInfo: RoomUserInfoShort | RoomUserInfo;
|
||||
}): void {
|
||||
const self = this;
|
||||
this.appOrganizationService
|
||||
.getUserInfo({ userSeq: String(params.senderInfo.seq), user: this.user })
|
||||
.then((rst) => {
|
||||
let isValid = false;
|
||||
if (
|
||||
!!rst &&
|
||||
!!rst.userInfo &&
|
||||
!!self.userPermission &&
|
||||
self.userPermission.fileTransferAllowedCompanyList.indexOf(
|
||||
rst.userInfo.companyCode
|
||||
) > -1
|
||||
) {
|
||||
isValid = true;
|
||||
}
|
||||
|
||||
if (!!isValid) {
|
||||
if (
|
||||
params.type === 'saveAs' &&
|
||||
self.loginSession.deviceType === DeviceType.PC
|
||||
) {
|
||||
self.nativeService
|
||||
.file_selectForSave({ defaultPath: params.fileInfo.fileName })
|
||||
.then((result) => {
|
||||
if (!!result) {
|
||||
if (!!result.canceled) {
|
||||
// 취소함.
|
||||
} else {
|
||||
self.appFileService.saveFile(
|
||||
{
|
||||
fileInfo: params.fileInfo,
|
||||
fileDownloadItem: params.fileDownloadItem,
|
||||
type: params.type,
|
||||
fileName: params.fileInfo.fileName,
|
||||
fileDownloadUrl: undefined,
|
||||
savePath: result.filePath
|
||||
},
|
||||
self.loginInfo,
|
||||
self.user,
|
||||
self.loginSession
|
||||
);
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((reason) => {
|
||||
// self.snackBarService.open(
|
||||
// self.translateService.instant(
|
||||
// 'common:file.errors.failToSpecifyPath'
|
||||
// ),
|
||||
// self.translateService.instant('common:file.errors.label')
|
||||
// );
|
||||
});
|
||||
} else {
|
||||
self.appFileService.saveFile(
|
||||
{
|
||||
fileInfo: params.fileInfo,
|
||||
fileDownloadItem: params.fileDownloadItem,
|
||||
type: params.type,
|
||||
fileName: params.fileInfo.fileName,
|
||||
fileDownloadUrl: undefined,
|
||||
savePath: undefined
|
||||
},
|
||||
self.loginInfo,
|
||||
self.user,
|
||||
self.loginSession
|
||||
);
|
||||
}
|
||||
} else {
|
||||
self._openAlert(
|
||||
self.i18nService.t('common:file.errors.disapprovalCompany')
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch((reason) => {
|
||||
self._openAlert(
|
||||
self.i18nService.t('common:file.errors.disapprovalCompany')
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private _standByRoomSetting(result: SettingDialogResult) {
|
||||
|
@ -640,4 +955,33 @@ export class MessageSectionComponent
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
onJoinConference(conferenceSeq: number): void {
|
||||
const loginSession = this.appAuthenticationService.getLoginSession();
|
||||
const req: ConferenceJoinRequest = {
|
||||
userSeq: String(this.user.info.seq),
|
||||
deviceType: loginSession.deviceType,
|
||||
tokenKey: this.loginInfo.tokenString,
|
||||
conferenceSeq
|
||||
};
|
||||
this.appChatService.joinVideoConference(req);
|
||||
}
|
||||
|
||||
private _openAlert(msg: string) {
|
||||
this.dialog.open<AlertDialogComponent, AlertDialogData, AlertDialogResult>(
|
||||
AlertDialogComponent,
|
||||
{
|
||||
panelClass: 'min-create-dialog',
|
||||
data: {
|
||||
title: this.i18nService.t('common:file.errors.title'),
|
||||
message: msg
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
resetRecentMessage() {
|
||||
this.recentMessage = undefined;
|
||||
this.recentUserInfo = undefined;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,9 +12,17 @@
|
|||
#searchWordInput
|
||||
type="text"
|
||||
formControlName="searchInput"
|
||||
[matAutocomplete]="auto"
|
||||
(keyup.backspace)="onKeyupBackspace($event)"
|
||||
(keydown.enter)="onKeyDownEnter($event, searchWordInput.value)"
|
||||
/>
|
||||
<!-- <input
|
||||
matInput
|
||||
#searchWordInput
|
||||
type="text"
|
||||
formControlName="searchInput"
|
||||
[matAutocomplete]="auto"
|
||||
(keydown.enter)="onKeyDownEnter($event, searchWordInput.value)"
|
||||
/> -->
|
||||
<mat-autocomplete #auto="matAutocomplete">
|
||||
<mat-option
|
||||
*ngFor="let filteredRecommendedWord of filteredRecommendedWordList"
|
||||
|
|
|
@ -9,7 +9,8 @@ import {
|
|||
EventEmitter,
|
||||
ChangeDetectorRef,
|
||||
ChangeDetectionStrategy,
|
||||
ViewChild
|
||||
ViewChild,
|
||||
ElementRef
|
||||
} from '@angular/core';
|
||||
import { FormGroup, FormBuilder } from '@angular/forms';
|
||||
|
||||
|
@ -17,7 +18,7 @@ import { Store, select } from '@ngrx/store';
|
|||
|
||||
import { MatAutocompleteTrigger } from '@angular/material/autocomplete';
|
||||
|
||||
import { User } from '@ucap/protocol-info';
|
||||
import { User } from '@ucap/domain-organization';
|
||||
|
||||
import { LogService } from '@ucap/ng-logger';
|
||||
|
||||
|
@ -45,6 +46,8 @@ export class SearchSectionComponent implements OnInit, OnDestroy {
|
|||
recommendedWordList: string[];
|
||||
filteredRecommendedWordList: string[];
|
||||
|
||||
@ViewChild('searchWordInput', { static: true })
|
||||
searchWordInput: ElementRef<HTMLInputElement>;
|
||||
@ViewChild(MatAutocompleteTrigger) autocomplete: MatAutocompleteTrigger;
|
||||
|
||||
private ngOnDestroySubject: Subject<void> = new Subject();
|
||||
|
@ -148,11 +151,20 @@ export class SearchSectionComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
}
|
||||
|
||||
onKeyupBackspace(event: Event) {
|
||||
if (this.searchWordInput.nativeElement.value === '') {
|
||||
this.searchCancel.emit();
|
||||
}
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
onKeyDownEnter(event: KeyboardEvent, searchWord: string) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
this.autocomplete.closePanel();
|
||||
if (!!this.autocomplete) {
|
||||
this.autocomplete.closePanel();
|
||||
}
|
||||
|
||||
this.keyDownEnter.emit({ searchWord });
|
||||
}
|
||||
|
|
|
@ -6,19 +6,19 @@
|
|||
>
|
||||
<div appLayoutsDefaultDialog="header">
|
||||
<span *ngIf="stepper.selectedIndex === 0">
|
||||
{{ 'dialog.title.newChatRoom' | ucapI18n }}
|
||||
{{ 'chat:dialog.title.newChatRoom' | ucapI18n }}
|
||||
</span>
|
||||
<span *ngIf="stepper.selectedIndex !== 0">
|
||||
{{ (!!isTimer ? 'dialog.timerRoom' : 'dialog.normalRoom') | ucapI18n }}
|
||||
{{ (!!isTimer ? 'chat:dialog.timerRoom' : 'chat:dialog.normalRoom') | ucapI18n }}
|
||||
</span>
|
||||
<div appLayoutsDefaultDialog="sub-header" class="sub-header-tit">
|
||||
<span appLayoutsDefaultDialog="sub-header" class="sub-header-tit">
|
||||
<span *ngIf="stepper.selectedIndex === 0">
|
||||
{{ 'dialog.title.subSelectRoomType' | ucapI18n }}
|
||||
{{ 'chat:dialog.title.subSelectRoomType' | ucapI18n }}
|
||||
</span>
|
||||
<span *ngIf="stepper.selectedIndex !== 0">
|
||||
{{ 'dialog.title.subSelectUser' | ucapI18n }}
|
||||
{{ 'chat:dialog.title.subSelectUser' | ucapI18n }}
|
||||
</span>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="dialog-body" appLayoutsDefaultDialog="body">
|
||||
|
@ -31,12 +31,12 @@
|
|||
<mat-step label="Select room type" fxFlexFill>
|
||||
<div class="ucap-dialog-select-room-type">
|
||||
<div class="normal-room room-type">
|
||||
<span class="title">{{ 'dialog.normalRoom' | ucapI18n }}</span>
|
||||
<span class="title">{{ 'chat:dialog.normalRoom' | ucapI18n }}</span>
|
||||
<div class="img"></div>
|
||||
<div
|
||||
class="description"
|
||||
[innerHTML]="
|
||||
'dialog.normalRoomDescription'
|
||||
'chat:dialog.normalRoomDescription'
|
||||
| ucapI18n: { maxCount: maxChatRoomUser }
|
||||
"
|
||||
></div>
|
||||
|
@ -69,12 +69,12 @@
|
|||
</div>
|
||||
|
||||
<div class="room-type timer-room">
|
||||
<span class="title">{{ 'dialog.timerRoom' | ucapI18n }}</span>
|
||||
<span class="title">{{ 'chat:dialog.timerRoom' | ucapI18n }}</span>
|
||||
<div class="img"></div>
|
||||
<div
|
||||
class="description"
|
||||
[innerHTML]="
|
||||
'dialog.timerRoomDescription'
|
||||
'chat:dialog.timerRoomDescription'
|
||||
| ucapI18n: { maxCount: maxChatRoomUser }
|
||||
"
|
||||
></div>
|
||||
|
@ -113,8 +113,9 @@
|
|||
[isDialog]="true"
|
||||
[checkable]="true"
|
||||
[selectedUserList]="selectedUserList"
|
||||
(toggleCheckUser)="onChangeUserList($event)"
|
||||
(toggleCheckGroup)="onChangeGroupList($event)"
|
||||
[filteredTimerChatAuth]="isTimer"
|
||||
(toggleCheckUser)="onToggleCheckUser($event)"
|
||||
(toggleCheckGroup)="onToggleCheckGroup($event)"
|
||||
></app-group-select-user>
|
||||
</div>
|
||||
<div class="ucap-dialog-organization-profile-selection">
|
||||
|
@ -130,7 +131,7 @@
|
|||
class="selected-head-area"
|
||||
>
|
||||
<p>
|
||||
{{ 'dialog.selectedUserList' | ucapI18n }}
|
||||
{{ 'chat:dialog.selectedUserList' | ucapI18n }}
|
||||
</p>
|
||||
<span
|
||||
>(<em class="number">{{ selectedUserList?.length }}</em
|
||||
|
@ -144,7 +145,7 @@
|
|||
</div>
|
||||
<div appLayoutsDefaultDialog="action" class="btn-box">
|
||||
<button mat-button mat-stroked-button (click)="onCancel(stepper)">
|
||||
{{ 'dialog.button.cancel' | ucapI18n }}
|
||||
{{ 'chat:dialog.button.cancel' | ucapI18n }}
|
||||
</button>
|
||||
<button
|
||||
mat-flat-button
|
||||
|
@ -153,7 +154,7 @@
|
|||
[disabled]="this.isTimer === undefined"
|
||||
(click)="onConfirm(stepper)"
|
||||
>
|
||||
{{ 'dialog.button.selectRoomUser' | ucapI18n }}
|
||||
{{ 'chat:dialog.button.selectRoomUser' | ucapI18n }}
|
||||
</button>
|
||||
<button
|
||||
mat-flat-button
|
||||
|
@ -162,7 +163,7 @@
|
|||
[disabled]="selectedUserList.length === 0"
|
||||
(click)="onOpenRoom(stepper)"
|
||||
>
|
||||
{{ 'dialog.button.openRoom' | ucapI18n }}
|
||||
{{ 'chat:dialog.button.openRoom' | ucapI18n }}
|
||||
</button>
|
||||
</div>
|
||||
</app-layouts-default-dialog>
|
||||
|
|
|
@ -80,7 +80,7 @@
|
|||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 48%;
|
||||
height: 210px;
|
||||
height: 200px;
|
||||
border: 1px solid #999999;
|
||||
background-color: #f7f8fa;
|
||||
text-align: center;
|
||||
|
@ -98,7 +98,7 @@
|
|||
width: 60px;
|
||||
height: 60px;
|
||||
margin-bottom: 10px;
|
||||
background-image: url(../../../../assets/images/ico/icon_normal_chat_g60.svg);
|
||||
background-image: url(/assets/images/ico/icon_normal_chat_g60.svg);
|
||||
}
|
||||
}
|
||||
&.timer-room {
|
||||
|
@ -106,7 +106,7 @@
|
|||
width: 60px;
|
||||
height: 60px;
|
||||
margin-bottom: 10px;
|
||||
background-image: url(../../../../assets/images/ico/icon_timer_chat_g60.svg);
|
||||
background-image: url(/assets/images/ico/icon_timer_chat_g60.svg);
|
||||
}
|
||||
}
|
||||
.selecter {
|
||||
|
|
|
@ -6,9 +6,7 @@ import {
|
|||
OnDestroy,
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Inject,
|
||||
Input,
|
||||
ViewChild
|
||||
Inject
|
||||
} from '@angular/core';
|
||||
|
||||
import {
|
||||
|
@ -17,32 +15,24 @@ import {
|
|||
MatDialog
|
||||
} from '@angular/material/dialog';
|
||||
|
||||
import { UserInfo, GroupDetailData } from '@ucap/protocol-sync';
|
||||
import {
|
||||
UserInfoSS,
|
||||
UserInfoF,
|
||||
UserInfoDN,
|
||||
AuthResponse
|
||||
} from '@ucap/protocol-query';
|
||||
import { UserInfo as RoomUserInfo } from '@ucap/protocol-room';
|
||||
import { UserInfo, UserInfoSS } from '@ucap/domain-organization';
|
||||
import { GroupInfoDetail } from '@ucap/domain-group';
|
||||
|
||||
import { MatStepper } from '@angular/material/stepper';
|
||||
import { I18nService } from '@ucap/ng-i18n';
|
||||
import {
|
||||
AlertDialogComponent,
|
||||
AlertDialogData,
|
||||
AlertDialogResult
|
||||
} from '@ucap/ng-ui';
|
||||
} from '@ucap/ng-ui/core';
|
||||
import { environment } from '@environments';
|
||||
import { Store, select } from '@ngrx/store';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { AuthorizationSelector } from '@ucap/ng-store-authentication';
|
||||
|
||||
export type UserInfoTypes =
|
||||
| UserInfo
|
||||
| UserInfoSS
|
||||
| UserInfoF
|
||||
| UserInfoDN
|
||||
| RoomUserInfo;
|
||||
import { AppGroupService } from '@app/services/app-group.service';
|
||||
import { UserInfoTypes } from '@app/types';
|
||||
import { AppChatService } from '@app/services/app-chat.service';
|
||||
import { UserPermission } from '@ucap/domain-authorization';
|
||||
|
||||
export interface CreateDialogData {}
|
||||
export interface CreateDialogResult {
|
||||
|
@ -62,7 +52,7 @@ export class CreateDialogComponent implements OnInit, OnDestroy {
|
|||
|
||||
isTimer: boolean | undefined;
|
||||
selectedUserList: UserInfoTypes[] = [];
|
||||
authRes: AuthResponse;
|
||||
userPermission: UserPermission;
|
||||
|
||||
private ngOnDestroySubject: Subject<void> = new Subject();
|
||||
|
||||
|
@ -72,7 +62,9 @@ export class CreateDialogComponent implements OnInit, OnDestroy {
|
|||
private i18nService: I18nService,
|
||||
public dialog: MatDialog,
|
||||
private store: Store<any>,
|
||||
private changeDetectorRef: ChangeDetectorRef
|
||||
private changeDetectorRef: ChangeDetectorRef,
|
||||
private appGroupService: AppGroupService,
|
||||
private appChatService: AppChatService
|
||||
) {
|
||||
this.maxChatRoomUser = environment.productConfig.chat.maxChatRoomUser;
|
||||
}
|
||||
|
@ -81,11 +73,11 @@ export class CreateDialogComponent implements OnInit, OnDestroy {
|
|||
this.store
|
||||
.pipe(
|
||||
takeUntil(this.ngOnDestroySubject),
|
||||
select(AuthorizationSelector.authResponse)
|
||||
select(AuthorizationSelector.userPermission)
|
||||
)
|
||||
.subscribe((authRes) => {
|
||||
this.authRes = authRes;
|
||||
if (!!this.authRes && !this.authRes.canTimerChat) {
|
||||
.subscribe((userPermission) => {
|
||||
this.userPermission = userPermission;
|
||||
if (!!this.userPermission && !this.userPermission.canTimerChat) {
|
||||
this.isTimer = false;
|
||||
this.currentStep = 1;
|
||||
}
|
||||
|
@ -103,7 +95,7 @@ export class CreateDialogComponent implements OnInit, OnDestroy {
|
|||
this.dialogRef.close();
|
||||
}
|
||||
onCancel(stepper: MatStepper) {
|
||||
if (!!this.authRes && !this.authRes.canTimerChat) {
|
||||
if (!!this.userPermission && !this.userPermission.canTimerChat) {
|
||||
// close.
|
||||
} else if (stepper.selectedIndex > 0) {
|
||||
stepper.previous();
|
||||
|
@ -135,93 +127,51 @@ export class CreateDialogComponent implements OnInit, OnDestroy {
|
|||
|
||||
this.selectedUserList.map((user) => userSeqs.push(user.seq.toString()));
|
||||
|
||||
// validation and openRoom
|
||||
this.appChatService.newOpenRoom(userSeqs, this.isTimer);
|
||||
|
||||
if (this.selectedUserList.length >= this.maxChatRoomUser) {
|
||||
this.dialog.open<
|
||||
AlertDialogComponent,
|
||||
AlertDialogData,
|
||||
AlertDialogResult
|
||||
>(AlertDialogComponent, {
|
||||
panelClass: 'min-create-dialog',
|
||||
data: {
|
||||
title: this.i18nService.t('chat:errors.label'),
|
||||
html: this.i18nService.t('chat:errors.maxCountOfRoomMemberWith', {
|
||||
maxCount: this.maxChatRoomUser
|
||||
})
|
||||
}
|
||||
});
|
||||
// not close popup..
|
||||
return;
|
||||
}
|
||||
|
||||
// Open Room.
|
||||
this.dialogRef.close({ userSeqs, isTimer: this.isTimer });
|
||||
}
|
||||
|
||||
onChangeUserList(datas: { checked: boolean; userInfo: UserInfoSS }[]) {
|
||||
if (!datas || 0 === datas.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const pushs: UserInfoSS[] = [];
|
||||
const pops: UserInfoSS[] = [];
|
||||
|
||||
datas.forEach((d) => {
|
||||
const i = this.selectedUserList.findIndex(
|
||||
(u) => String(u.seq) === String(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.selectedUserList = [...this.selectedUserList, ...pushs];
|
||||
}
|
||||
|
||||
if (0 < pops.length) {
|
||||
this.selectedUserList = this.selectedUserList.filter(
|
||||
(u) => -1 === pops.findIndex((p) => String(p.seq) === String(u.seq))
|
||||
);
|
||||
}
|
||||
}
|
||||
onChangeGroupList(params: {
|
||||
isChecked: boolean;
|
||||
groupBuddyList: { group: GroupDetailData; buddyList: UserInfo[] };
|
||||
}) {
|
||||
if (params.isChecked) {
|
||||
params.groupBuddyList.buddyList.forEach((item) => {
|
||||
if (
|
||||
this.selectedUserList.filter(
|
||||
(user) => String(user.seq) === String(item.seq)
|
||||
).length === 0
|
||||
) {
|
||||
this.selectedUserList = [...this.selectedUserList, item];
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.selectedUserList = this.selectedUserList.filter(
|
||||
(item) =>
|
||||
params.groupBuddyList.buddyList.filter(
|
||||
(del) => String(del.seq) === String(item.seq)
|
||||
).length === 0
|
||||
);
|
||||
this.dialogRef.close({ userSeqs, isTimer: this.isTimer });
|
||||
}
|
||||
}
|
||||
onRemovedProfileSelection(userInfo: UserInfo) {
|
||||
const i = this.selectedUserList.findIndex(
|
||||
(u) => String(u.seq) === String(userInfo.seq)
|
||||
|
||||
onToggleCheckUser(datas: { checked: boolean; userInfo: UserInfoSS }[]) {
|
||||
const resList = this.appGroupService.getToggleCheckUser(
|
||||
datas,
|
||||
this.selectedUserList
|
||||
);
|
||||
if (!resList) {
|
||||
return;
|
||||
}
|
||||
this.selectedUserList = resList;
|
||||
}
|
||||
onToggleCheckGroup(params: {
|
||||
isChecked: boolean;
|
||||
groupBuddyList: { group: GroupInfoDetail; buddyList: UserInfo[] };
|
||||
}) {
|
||||
const resList = this.appGroupService.getToggleCheckGroup(
|
||||
params,
|
||||
this.selectedUserList
|
||||
);
|
||||
|
||||
if (-1 < i) {
|
||||
this.selectedUserList = this.selectedUserList.filter(
|
||||
(u) => String(u.seq) !== String(userInfo.seq)
|
||||
);
|
||||
if (!resList) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.selectedUserList = resList;
|
||||
}
|
||||
onRemovedProfileSelection(userInfo: UserInfo) {
|
||||
const resUserList = this.appGroupService.removedProfileSelection(
|
||||
userInfo,
|
||||
this.selectedUserList
|
||||
);
|
||||
|
||||
if (!resUserList) {
|
||||
}
|
||||
this.selectedUserList = resUserList;
|
||||
}
|
||||
removableForSelection = (userInfo: UserInfo) => {
|
||||
return true;
|
||||
|
|
|
@ -7,23 +7,25 @@ import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
|||
|
||||
import { select, Store } from '@ngrx/store';
|
||||
|
||||
import { DeviceType, LoginSession } from '@ucap/core';
|
||||
import { FileDownloadItem } from '@ucap/api';
|
||||
import { LoginResponse } from '@ucap/protocol-authentication';
|
||||
import { FileEventJson } from '@ucap/protocol-event';
|
||||
import { FileInfo, isMedia } from '@ucap/protocol-file';
|
||||
import { User } from '@ucap/protocol-info';
|
||||
import { DeviceType, FileDownloadItem } from '@ucap/domain-common';
|
||||
import { User } from '@ucap/domain-organization';
|
||||
import { LoginSession, LoginInfo } from '@ucap/domain-authentication';
|
||||
import { FileEventJson, FileInfo, isMedia } from '@ucap/domain-chat';
|
||||
|
||||
import { LogService } from '@ucap/ng-logger';
|
||||
import { CommonApiService } from '@ucap/ng-api-common';
|
||||
|
||||
import { UserSelector } from '@ucap/ng-store-organization';
|
||||
import { LoginSelector } from '@ucap/ng-store-authentication';
|
||||
import {
|
||||
LoginSelector,
|
||||
AuthorizationSelector
|
||||
} from '@ucap/ng-store-authentication';
|
||||
|
||||
import { SelectFileInfo } from '@ucap/ng-ui';
|
||||
import { SelectFileInfo } from '@ucap/ng-ui/viewer';
|
||||
|
||||
import { AppFileService } from '@app/services/app-file.service';
|
||||
import { AppAuthenticationService } from '@app/services/app-authentication.service';
|
||||
import { UserPermission } from '@ucap/domain-authorization';
|
||||
|
||||
export interface FileViewerDialogData {
|
||||
fileInfos: FileInfo[];
|
||||
|
@ -51,9 +53,10 @@ export class FileViewerDialogComponent implements OnInit, OnDestroy {
|
|||
};
|
||||
currentFileInfo: FileInfo;
|
||||
|
||||
loginRes: LoginResponse;
|
||||
loginInfo: LoginInfo;
|
||||
user: User;
|
||||
loginSession: LoginSession;
|
||||
userPermission: UserPermission;
|
||||
|
||||
constructor(
|
||||
private store: Store<any>,
|
||||
|
@ -96,14 +99,54 @@ export class FileViewerDialogComponent implements OnInit, OnDestroy {
|
|||
|
||||
ngOnInit() {
|
||||
this.store
|
||||
.pipe(takeUntil(this.ngOnDestroySubject), select(LoginSelector.loginRes))
|
||||
.subscribe((loginRes) => (this.loginRes = loginRes));
|
||||
.pipe(takeUntil(this.ngOnDestroySubject), select(LoginSelector.loginInfo))
|
||||
.subscribe((loginInfo) => (this.loginInfo = loginInfo));
|
||||
|
||||
this.store
|
||||
.pipe(takeUntil(this.ngOnDestroySubject), select(UserSelector.user))
|
||||
.subscribe((user) => (this.user = user));
|
||||
|
||||
this.loginSession = this.appAuthenticationService.getLoginSession();
|
||||
|
||||
// auth.fileTransferAllowedCompanyList check.
|
||||
this.store
|
||||
.pipe(
|
||||
takeUntil(this.ngOnDestroySubject),
|
||||
select(AuthorizationSelector.userPermission)
|
||||
)
|
||||
.subscribe((userPermission) => {
|
||||
if (!!userPermission) {
|
||||
this.userPermission = userPermission;
|
||||
}
|
||||
|
||||
if (
|
||||
!!userPermission &&
|
||||
!!this.data.fileInfos &&
|
||||
this.data.fileInfos.length > 0
|
||||
) {
|
||||
this.fileInfo = {
|
||||
fileInfos: this.data.fileInfos
|
||||
.filter((item) => {
|
||||
// filtered userPermission.fileTransferAllowedCompanyList
|
||||
if (
|
||||
!!userPermission.fileTransferAllowedCompanyList &&
|
||||
userPermission.fileTransferAllowedCompanyList.length > 0
|
||||
) {
|
||||
return (
|
||||
userPermission.fileTransferAllowedCompanyList.indexOf(
|
||||
item.sentMessageJson.companyCode
|
||||
) > -1
|
||||
);
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.sort((a, b) =>
|
||||
a.eventSeq < b.eventSeq ? 1 : a.eventSeq > b.eventSeq ? -1 : 0
|
||||
),
|
||||
selectFileInfo: this.data.selectFileInfo
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
|
@ -147,7 +190,7 @@ export class FileViewerDialogComponent implements OnInit, OnDestroy {
|
|||
fileDownloadUrl: undefined,
|
||||
savePath: undefined
|
||||
},
|
||||
this.loginRes,
|
||||
this.loginInfo,
|
||||
this.user,
|
||||
this.loginSession
|
||||
);
|
||||
|
|
|
@ -10,9 +10,14 @@
|
|||
<div class="dialog-body" appLayoutsDefaultDialog="body" fxFlexFill>
|
||||
<div class="ucap-dialog-app-group-select-user">
|
||||
<!-- search start-->
|
||||
<div class="ucap-dialog-search">
|
||||
<div
|
||||
*ngIf="currentTabIndex === 0"
|
||||
class="ucap-dialog-search"
|
||||
[ngClass]="currentTabIndex === 0 ? 'ucap-dialog-search-disable' : ''"
|
||||
>
|
||||
<app-organization-search-for-tenant
|
||||
placeholder="이름, 부서명, 전화번호, 이메일"
|
||||
[isBackspaceCanceled]="isBackspaceCanceled"
|
||||
[(searchData)]="companySearchData"
|
||||
(canceled)="onCanceled()"
|
||||
class="select-user-section-search"
|
||||
|
@ -24,7 +29,7 @@
|
|||
<mat-tab-group
|
||||
mat-stretch-tabs
|
||||
class="tap-container tab_num2"
|
||||
(selectedIndexChange)="onSelectedIndexChange($event)"
|
||||
[(selectedIndex)]="currentTabIndex"
|
||||
>
|
||||
<!--[S]그룹-->
|
||||
<mat-tab>
|
||||
|
@ -57,6 +62,8 @@
|
|||
<div fxFlexFill class="ucap-dialog-chat-tap">
|
||||
<perfect-scrollbar style="width: 100%; height: 100%;">
|
||||
<app-chat-room-list
|
||||
fxFlexFill
|
||||
[selectedRoom]="selectedRoom"
|
||||
[checkable]="true"
|
||||
(toggleRoom)="onToggleRoom($event)"
|
||||
></app-chat-room-list>
|
||||
|
@ -81,12 +88,13 @@
|
|||
<div class="search-result-list">
|
||||
<perfect-scrollbar style="width: 100%; height: 100%;">
|
||||
<app-group-profile-list
|
||||
#appProfileList
|
||||
[searchData]="companySearchData"
|
||||
[selectedUser]="selectedUserList"
|
||||
[checkable]="true"
|
||||
[isDialog]="true"
|
||||
(searched)="onSearched($event)"
|
||||
(toggleCheck)="onToggleCheckUser($event)"
|
||||
(toggleCheckUser)="onToggleCheckUser($event)"
|
||||
class="ucap-dialog-search-result-container"
|
||||
></app-group-profile-list>
|
||||
</perfect-scrollbar>
|
||||
|
@ -127,12 +135,7 @@
|
|||
<button
|
||||
mat-flat-button
|
||||
class="bg-primary-darkest"
|
||||
[disabled]="
|
||||
!(
|
||||
!!selectedRoom ||
|
||||
(!!selectedUserList && selectedUserList.length > 0)
|
||||
)
|
||||
"
|
||||
[disabled]="checkDisableBtn()"
|
||||
(click)="onConfirm()"
|
||||
>
|
||||
{{ 'dialog.button.save' | ucapI18n }}
|
||||
|
|
|
@ -18,13 +18,16 @@
|
|||
}
|
||||
|
||||
.forwrad-dialog-content {
|
||||
height: calc(100% - 50px);
|
||||
flex: 1 1 auto;
|
||||
// height: calc(100% - 50px);
|
||||
.tap-container {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.ucap-dialog-app-group-select-user {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1 0 auto;
|
||||
//width: 60%;
|
||||
height: 100%;
|
||||
|
@ -35,6 +38,9 @@
|
|||
height: 78%;
|
||||
margin-bottom: 2%;
|
||||
}
|
||||
.ucap-dialog-search {
|
||||
flex: 0 0 50px;
|
||||
}
|
||||
}
|
||||
.ucap-dialog-organization-profile-selection {
|
||||
position: relative;
|
||||
|
|
|
@ -19,10 +19,13 @@ import {
|
|||
|
||||
import { Store, select } from '@ngrx/store';
|
||||
|
||||
import { VersionInfo2Response } from '@ucap/api-public';
|
||||
import { UserInfo, GroupDetailData } from '@ucap/protocol-sync';
|
||||
import { UserInfoSS, UserInfoF, UserInfoDN } from '@ucap/protocol-query';
|
||||
import { UserInfo as RoomUserInfo, RoomInfo } from '@ucap/protocol-room';
|
||||
import {
|
||||
UserInfo,
|
||||
UserInfoSS,
|
||||
UserInfoF,
|
||||
UserInfoDN
|
||||
} from '@ucap/domain-organization';
|
||||
import { UserInfo as RoomUserInfo, RoomInfo } from '@ucap/domain-chat';
|
||||
|
||||
import { I18nService } from '@ucap/ng-i18n';
|
||||
|
||||
|
@ -33,18 +36,16 @@ import {
|
|||
AlertDialogComponent,
|
||||
AlertDialogData,
|
||||
AlertDialogResult
|
||||
} from '@ucap/ng-ui';
|
||||
} from '@ucap/ng-ui/core';
|
||||
|
||||
import { SearchData } from '@app/ucap/organization/models/search-data';
|
||||
import { Expansion02Component as AppExpansion02Component } from '@app/ucap/group/components/expansion-02.component';
|
||||
import { ProfileListComponent as AppProfileListComponent } from '@app/ucap/group/components/profile-list.component';
|
||||
import { environment } from '@environments';
|
||||
|
||||
export type UserInfoTypes =
|
||||
| UserInfo
|
||||
| UserInfoSS
|
||||
| UserInfoF
|
||||
| UserInfoDN
|
||||
| RoomUserInfo;
|
||||
import { AppGroupService } from '@app/services/app-group.service';
|
||||
import { UserInfoTypes } from '@app/types';
|
||||
import { VersionInfo } from '@ucap/domain-authentication';
|
||||
import { GroupInfoDetail } from '@ucap/domain-group';
|
||||
|
||||
export interface ForwardDialogData {}
|
||||
export interface ForwardDialogResult {
|
||||
|
@ -63,6 +64,9 @@ export class ForwardDialogComponent implements OnInit, OnDestroy {
|
|||
@ViewChild('appGroupExpansion', { static: false })
|
||||
appGroupExpansion: AppExpansion02Component;
|
||||
|
||||
@ViewChild('appProfileList', { static: false })
|
||||
appProfileList: AppProfileListComponent;
|
||||
|
||||
set companySearchData(searchData: SearchData) {
|
||||
if (!!searchData && searchData.searchWord !== '') {
|
||||
this._companySearchData = { ...searchData, bySearch: true };
|
||||
|
@ -85,13 +89,23 @@ export class ForwardDialogComponent implements OnInit, OnDestroy {
|
|||
selectedRoom: RoomInfo;
|
||||
selectedUserList: UserInfoTypes[] = [];
|
||||
|
||||
versionInfo2Res: VersionInfo2Response;
|
||||
|
||||
groupList: GroupDetailData[];
|
||||
versionInfo: VersionInfo;
|
||||
|
||||
groupList: GroupInfoDetail[];
|
||||
isBackspaceCanceled = true;
|
||||
isSearch = false;
|
||||
searchedList: UserInfoSS[] = [];
|
||||
currentTabIndex: number;
|
||||
|
||||
set currentTabIndex(idx: number) {
|
||||
this._currentTabIndex = idx;
|
||||
// this._resetSelectedObject();
|
||||
}
|
||||
|
||||
get currentTabIndex() {
|
||||
return this._currentTabIndex;
|
||||
}
|
||||
// tslint:disable-next-line: variable-name
|
||||
_currentTabIndex: number;
|
||||
|
||||
constructor(
|
||||
public dialogRef: MatDialogRef<ForwardDialogData, ForwardDialogResult>,
|
||||
|
@ -99,7 +113,8 @@ export class ForwardDialogComponent implements OnInit, OnDestroy {
|
|||
private store: Store<any>,
|
||||
private i18nService: I18nService,
|
||||
public dialog: MatDialog,
|
||||
private changeDetectorRef: ChangeDetectorRef
|
||||
private changeDetectorRef: ChangeDetectorRef,
|
||||
private appGroupService: AppGroupService
|
||||
) {
|
||||
this.maxChatRoomUser = environment.productConfig.chat.maxChatRoomUser;
|
||||
}
|
||||
|
@ -108,10 +123,10 @@ export class ForwardDialogComponent implements OnInit, OnDestroy {
|
|||
this.store
|
||||
.pipe(
|
||||
takeUntil(this.ngOnDestroySubject),
|
||||
select(ConfigurationSelector.versionInfo2Response)
|
||||
select(ConfigurationSelector.versionInfo)
|
||||
)
|
||||
.subscribe((versionInfo2Res) => {
|
||||
this.versionInfo2Res = versionInfo2Res;
|
||||
.subscribe((versionInfo) => {
|
||||
this.versionInfo = versionInfo;
|
||||
});
|
||||
|
||||
this.store
|
||||
|
@ -119,6 +134,7 @@ export class ForwardDialogComponent implements OnInit, OnDestroy {
|
|||
.subscribe((groups) => {
|
||||
this.groupList = groups;
|
||||
});
|
||||
this.currentTabIndex = 0;
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
|
@ -147,68 +163,49 @@ export class ForwardDialogComponent implements OnInit, OnDestroy {
|
|||
|
||||
onSearched(searchedUserInfos: UserInfoSS[]): void {
|
||||
this.searchedList = searchedUserInfos;
|
||||
|
||||
if (!!this.appProfileList) {
|
||||
this.appProfileList.psUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
onToggleCheckUser(datas: { checked: boolean; userInfo: UserInfoSS }[]) {
|
||||
if (!datas || 0 === datas.length) {
|
||||
const resList = this.appGroupService.getToggleCheckUser(
|
||||
datas,
|
||||
this.selectedUserList
|
||||
);
|
||||
|
||||
if (!resList) {
|
||||
return;
|
||||
}
|
||||
|
||||
const pushs: UserInfoSS[] = [];
|
||||
const pops: UserInfoSS[] = [];
|
||||
|
||||
datas.forEach((d) => {
|
||||
const i = this.selectedUserList.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.selectedUserList = [...this.selectedUserList, ...pushs];
|
||||
}
|
||||
|
||||
if (0 < pops.length) {
|
||||
this.selectedUserList = this.selectedUserList.filter(
|
||||
(u) => -1 === pops.findIndex((p) => p.seq === u.seq)
|
||||
);
|
||||
}
|
||||
this.selectedUserList = resList;
|
||||
}
|
||||
|
||||
onToggleCheckGroup(params: {
|
||||
isChecked: boolean;
|
||||
groupBuddyList: { group: GroupDetailData; buddyList: UserInfo[] };
|
||||
groupBuddyList: { group: GroupInfoDetail; 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
|
||||
);
|
||||
const resList = this.appGroupService.getToggleCheckGroup(
|
||||
params,
|
||||
this.selectedUserList
|
||||
);
|
||||
|
||||
if (!resList) {
|
||||
return;
|
||||
}
|
||||
this.selectedUserList = resList;
|
||||
}
|
||||
|
||||
onCancel() {
|
||||
this.dialogRef.close({ choice: false });
|
||||
}
|
||||
onConfirm() {
|
||||
if (this.currentTabIndex === 0) {
|
||||
this.selectedRoom = undefined;
|
||||
} else {
|
||||
this.selectedUserList = [];
|
||||
}
|
||||
|
||||
if (
|
||||
!this.selectedRoom &&
|
||||
!!this.selectedUserList &&
|
||||
|
@ -238,58 +235,8 @@ export class ForwardDialogComponent implements OnInit, OnDestroy {
|
|||
onToggleRoom(roomInfo: RoomInfo): void {
|
||||
if (!!roomInfo) {
|
||||
this.selectedRoom = roomInfo;
|
||||
}
|
||||
}
|
||||
|
||||
getCheckedByRoomInfo(roomInfo: RoomInfo): boolean {
|
||||
if (
|
||||
!!this.selectedRoom &&
|
||||
this.selectedRoom.roomId.localeCompare(roomInfo.roomId) === 0
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
onChangeUserList(data: { checked: boolean; userInfo: UserInfoSS }) {
|
||||
const i = this.selectedUserList.findIndex(
|
||||
(u) => String(u.seq) === String(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) => String(u.seq) !== String(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) => String(user.seq) === String(item.seq)
|
||||
).length === 0
|
||||
) {
|
||||
this.selectedUserList = [...this.selectedUserList, item];
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.selectedUserList = this.selectedUserList.filter(
|
||||
(item) =>
|
||||
params.groupBuddyList.buddyList.filter(
|
||||
(del) => String(del.seq) === String(item.seq)
|
||||
).length === 0
|
||||
);
|
||||
this.selectedRoom = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -321,31 +268,62 @@ export class ForwardDialogComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
onToggleSearchAllItem(value: boolean): void {
|
||||
const pushs: UserInfoSS[] = [];
|
||||
const pops: UserInfoSS[] = [];
|
||||
|
||||
this.searchedList.forEach((user) => {
|
||||
const i = this.selectedUserList.findIndex((u) => u.seq === user.seq);
|
||||
|
||||
if (-1 === i) {
|
||||
pushs.push(user);
|
||||
}
|
||||
|
||||
if (-1 < i) {
|
||||
pops.push(user);
|
||||
}
|
||||
});
|
||||
|
||||
if (!!value) {
|
||||
const targetRoomList = this.searchedList;
|
||||
this.selectedUserList = targetRoomList.slice();
|
||||
if (0 < pushs.length) {
|
||||
this.selectedUserList = [...this.selectedUserList, ...pushs];
|
||||
}
|
||||
} else {
|
||||
this.selectedUserList = [];
|
||||
if (0 < pops.length) {
|
||||
this.selectedUserList = this.selectedUserList.filter(
|
||||
(u) => -1 === pops.findIndex((p) => p.seq === u.seq)
|
||||
);
|
||||
}
|
||||
}
|
||||
this.changeDetectorRef.markForCheck();
|
||||
}
|
||||
|
||||
onCanceled() {
|
||||
this.isSearch = false;
|
||||
this.searchedList = [];
|
||||
|
||||
this.companySearchData = { ...this.companySearchData, searchWord: '' };
|
||||
}
|
||||
|
||||
checkDisableBtn(): boolean {
|
||||
if (
|
||||
this.currentTabIndex === 0 &&
|
||||
!!this.selectedUserList &&
|
||||
this.selectedUserList.length > 0
|
||||
) {
|
||||
return false;
|
||||
} else if (this.currentTabIndex === 1 && !!this.selectedRoom) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
onRemovedProfileSelection(userInfo: UserInfo) {
|
||||
const i = this.selectedUserList.findIndex(
|
||||
(u) => String(u.seq) === String(userInfo.seq)
|
||||
const resUserList = this.appGroupService.removedProfileSelection(
|
||||
userInfo,
|
||||
this.selectedUserList
|
||||
);
|
||||
|
||||
if (-1 < i) {
|
||||
this.selectedUserList = this.selectedUserList.filter(
|
||||
(u) => String(u.seq) !== String(userInfo.seq)
|
||||
);
|
||||
if (!resUserList) {
|
||||
}
|
||||
this.selectedUserList = resUserList;
|
||||
}
|
||||
removableForSelection = (userInfo: UserInfo) => {
|
||||
return true;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
|
||||
import {
|
||||
Component,
|
||||
|
@ -9,6 +10,8 @@ import {
|
|||
Inject
|
||||
} from '@angular/core';
|
||||
|
||||
import { Store, select } from '@ngrx/store';
|
||||
|
||||
import {
|
||||
MatDialogRef,
|
||||
MAT_DIALOG_DATA,
|
||||
|
@ -16,11 +19,9 @@ import {
|
|||
MatDialogConfig
|
||||
} from '@angular/material/dialog';
|
||||
|
||||
import { I18nService } from '@ucap/ng-i18n';
|
||||
import { RoomInfo } from '@ucap/domain-chat';
|
||||
|
||||
import { Store, select } from '@ngrx/store';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { RoomInfo } from '@ucap/protocol-room';
|
||||
import { I18nService } from '@ucap/ng-i18n';
|
||||
import { RoomSelector } from '@ucap/ng-store-chat';
|
||||
|
||||
export interface SettingDialogData {
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<div class="profile-image">
|
||||
<img
|
||||
ucapImage
|
||||
[base]="versionInfo2Res?.profileRoot"
|
||||
[base]="versionInfo?.profileRoot"
|
||||
[path]="userInfo.profileImageFile"
|
||||
[default]="defaultProfileImage"
|
||||
/>
|
||||
|
@ -32,7 +32,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="contents">
|
||||
<perfect-scrollbar
|
||||
<perfect-scrollbar #perfectScroll
|
||||
><div
|
||||
[innerHTML]="
|
||||
contents | ucapSafeHtml | ucapLinefeedToHtml | ucapLinky
|
||||
|
|
|
@ -5,7 +5,9 @@ import {
|
|||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Inject,
|
||||
ElementRef
|
||||
ElementRef,
|
||||
ViewChild,
|
||||
AfterViewInit
|
||||
} from '@angular/core';
|
||||
|
||||
import { Subject, of, combineLatest } from 'rxjs';
|
||||
|
@ -18,16 +20,18 @@ import {
|
|||
MatDialog
|
||||
} from '@angular/material/dialog';
|
||||
|
||||
import { DeviceType } from '@ucap/core';
|
||||
import { StatusCode } from '@ucap/api';
|
||||
import { NativeService } from '@ucap/native';
|
||||
import { VersionInfo2Response } from '@ucap/api-public';
|
||||
import { MassTalkDownloadRequest } from '@ucap/api-common';
|
||||
import { DeviceType } from '@ucap/domain-common';
|
||||
import {
|
||||
UserInfo as RoomUserInfo,
|
||||
UserInfoShort as RoomUserInfoShort
|
||||
} from '@ucap/protocol-room';
|
||||
import { Info, EventJson } from '@ucap/protocol-event';
|
||||
UserInfoShort as RoomUserInfoShort,
|
||||
Info,
|
||||
EventJson
|
||||
} from '@ucap/domain-chat';
|
||||
|
||||
import { StatusCode } from '@ucap/api';
|
||||
import { NativeService } from '@ucap/native';
|
||||
|
||||
import { MassTalkDownloadRequest } from '@ucap/api-common';
|
||||
|
||||
import { CommonApiService } from '@ucap/ng-api-common';
|
||||
import { LogService } from '@ucap/ng-logger';
|
||||
|
@ -36,6 +40,8 @@ import { RoomSelector } from '@ucap/ng-store-chat';
|
|||
import { ConfigurationSelector } from '@ucap/ng-store-authentication';
|
||||
|
||||
import { AppChatService } from '@app/services/app-chat.service';
|
||||
import { PerfectScrollbarComponent } from 'ngx-perfect-scrollbar';
|
||||
import { VersionInfo } from '@ucap/domain-authentication';
|
||||
|
||||
export type UserInfoTypes = RoomUserInfo | RoomUserInfoShort;
|
||||
|
||||
|
@ -55,13 +61,15 @@ export interface TextDetailDialogResult {}
|
|||
styleUrls: ['./text-detail.dialog.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class TextDetailDialogComponent implements OnInit, OnDestroy {
|
||||
export class TextDetailDialogComponent
|
||||
implements OnInit, OnDestroy, AfterViewInit {
|
||||
userInfo: UserInfoTypes;
|
||||
contents: string;
|
||||
contents = '';
|
||||
|
||||
defaultProfileImage: string;
|
||||
versionInfo2Res: VersionInfo2Response;
|
||||
versionInfo: VersionInfo;
|
||||
|
||||
@ViewChild('perfectScroll') perfectScroll: PerfectScrollbarComponent;
|
||||
private ngOnDestroySubject: Subject<void> = new Subject();
|
||||
|
||||
constructor(
|
||||
|
@ -85,10 +93,10 @@ export class TextDetailDialogComponent implements OnInit, OnDestroy {
|
|||
this.store
|
||||
.pipe(
|
||||
takeUntil(this.ngOnDestroySubject),
|
||||
select(ConfigurationSelector.versionInfo2Response)
|
||||
select(ConfigurationSelector.versionInfo)
|
||||
)
|
||||
.subscribe((versionInfo2Res) => {
|
||||
this.versionInfo2Res = versionInfo2Res;
|
||||
.subscribe((versionInfo) => {
|
||||
this.versionInfo = versionInfo;
|
||||
});
|
||||
|
||||
this.commonApiService
|
||||
|
@ -107,6 +115,7 @@ export class TextDetailDialogComponent implements OnInit, OnDestroy {
|
|||
this.changeDetectorRef.markForCheck();
|
||||
|
||||
setTimeout(() => {
|
||||
this.psUpdate();
|
||||
if (
|
||||
!!this.elementRef.nativeElement &&
|
||||
!!this.elementRef.nativeElement.querySelector('a')
|
||||
|
@ -154,6 +163,16 @@ export class TextDetailDialogComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.psUpdate();
|
||||
}
|
||||
|
||||
psUpdate() {
|
||||
if (!!this.perfectScroll) {
|
||||
this.perfectScroll.directiveRef.update();
|
||||
}
|
||||
}
|
||||
|
||||
onClickEvent(event: MouseEvent) {
|
||||
this.nativeService.platform_openDefaultBrowser(
|
||||
(event.target as HTMLAnchorElement).text
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<div class="profile-image">
|
||||
<img
|
||||
ucapImage
|
||||
[base]="versionInfo2Res?.profileRoot"
|
||||
[base]="versionInfo?.profileRoot"
|
||||
[path]="userInfo.profileImageFile"
|
||||
[default]="defaultProfileImage"
|
||||
/>
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
import { Subject, of, combineLatest } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
|
||||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
|
@ -9,7 +12,7 @@ import {
|
|||
AfterViewInit
|
||||
} from '@angular/core';
|
||||
|
||||
import { Subject, of, combineLatest } from 'rxjs';
|
||||
import { Store, select } from '@ngrx/store';
|
||||
|
||||
import {
|
||||
MatDialogRef,
|
||||
|
@ -17,21 +20,21 @@ import {
|
|||
MatDialog
|
||||
} from '@angular/material/dialog';
|
||||
|
||||
import { NativeService } from '@ucap/native';
|
||||
import { VersionInfo2Response } from '@ucap/api-public';
|
||||
|
||||
import {
|
||||
UserInfo as RoomUserInfo,
|
||||
UserInfoShort as RoomUserInfoShort
|
||||
} from '@ucap/protocol-room';
|
||||
UserInfoShort as RoomUserInfoShort,
|
||||
Info,
|
||||
MassTranslationEventJson
|
||||
} from '@ucap/domain-chat';
|
||||
|
||||
import { NativeService } from '@ucap/native';
|
||||
|
||||
import { LogService } from '@ucap/ng-logger';
|
||||
import { UCAP_NATIVE_SERVICE } from '@ucap/ng-native';
|
||||
import { Store, select } from '@ngrx/store';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
|
||||
import { ConfigurationSelector } from '@ucap/ng-store-authentication';
|
||||
import { RoomSelector } from '@ucap/ng-store-chat';
|
||||
import { Info, MassTranslationEventJson } from '@ucap/protocol-event';
|
||||
import { VersionInfo } from '@ucap/domain-authentication';
|
||||
|
||||
export type UserInfoTypes = RoomUserInfo | RoomUserInfoShort;
|
||||
|
||||
|
@ -55,7 +58,7 @@ export class TransDetailDialogComponent
|
|||
contents: string;
|
||||
|
||||
defaultProfileImage: string;
|
||||
versionInfo2Res: VersionInfo2Response;
|
||||
versionInfo: VersionInfo;
|
||||
|
||||
private ngOnDestroySubject: Subject<void> = new Subject();
|
||||
|
||||
|
@ -78,10 +81,10 @@ export class TransDetailDialogComponent
|
|||
this.store
|
||||
.pipe(
|
||||
takeUntil(this.ngOnDestroySubject),
|
||||
select(ConfigurationSelector.versionInfo2Response)
|
||||
select(ConfigurationSelector.versionInfo)
|
||||
)
|
||||
.subscribe((versionInfo2Res) => {
|
||||
this.versionInfo2Res = versionInfo2Res;
|
||||
.subscribe((versionInfo) => {
|
||||
this.versionInfo = versionInfo;
|
||||
});
|
||||
combineLatest([
|
||||
this.store.pipe(select(RoomSelector.roomUser, this.data.roomId)),
|
||||
|
|
179
src/app/sections/chat/directives/file-upload-for.directive.ts
Normal file
179
src/app/sections/chat/directives/file-upload-for.directive.ts
Normal file
|
@ -0,0 +1,179 @@
|
|||
import { Subject, fromEvent } from 'rxjs';
|
||||
|
||||
import {
|
||||
Directive,
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
HostListener,
|
||||
Output,
|
||||
Input,
|
||||
AfterViewInit,
|
||||
NgZone,
|
||||
OnDestroy,
|
||||
OnInit
|
||||
} from '@angular/core';
|
||||
|
||||
import { FileUploadItem } from '@ucap/domain-common';
|
||||
|
||||
import { FileUploadQueueComponent } from '@ucap/ng-ui/file-upload';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
|
||||
@Directive({
|
||||
selector: 'input[ucapFileUploadFor01], div[ucapFileUploadFor01]'
|
||||
})
|
||||
export class FileUploadForDirective
|
||||
implements OnInit, OnDestroy, AfterViewInit {
|
||||
@Input()
|
||||
fileUploadQueue?: FileUploadQueueComponent;
|
||||
|
||||
@Input()
|
||||
validator?: (fileList: FileList) => Promise<boolean>;
|
||||
|
||||
@Output()
|
||||
public fileDragEnter = new EventEmitter<DataTransferItemList>();
|
||||
|
||||
@Output()
|
||||
public fileDragOver = new EventEmitter<void>();
|
||||
|
||||
@Output()
|
||||
public fileDragLeave = new EventEmitter<void>();
|
||||
|
||||
@Output()
|
||||
public fileSelected = new EventEmitter<FileUploadItem[] | FileList>();
|
||||
|
||||
dragOver = false;
|
||||
|
||||
private ngOnDestroySubject: Subject<void> = new Subject();
|
||||
|
||||
constructor(
|
||||
private elementRef: ElementRef,
|
||||
private readonly ngZone: NgZone
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
fromEvent(window, 'dragenter')
|
||||
.pipe(takeUntil(this.ngOnDestroySubject))
|
||||
.subscribe((event: DragEvent) => {
|
||||
if (!this.isFileDrag(event.dataTransfer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.dragOver) {
|
||||
this.fileDragEnter.emit(event.dataTransfer.items);
|
||||
this.dragOver = true;
|
||||
if (!!this.fileUploadQueue) {
|
||||
this.fileUploadQueue.onDragEnter(event.dataTransfer.items);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
fromEvent(window, 'dragover')
|
||||
.pipe(takeUntil(this.ngOnDestroySubject))
|
||||
.subscribe((event: DragEvent) => {
|
||||
if (!this.isFileDrag(event.dataTransfer)) {
|
||||
return;
|
||||
}
|
||||
// if (this.fileUploadQueue.isEventInElement(event)) {
|
||||
// event.dataTransfer.dropEffect = 'copy';
|
||||
// } else {
|
||||
// event.dataTransfer.dropEffect = 'none';
|
||||
// }
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
fromEvent(window, 'dragleave')
|
||||
.pipe(takeUntil(this.ngOnDestroySubject))
|
||||
.subscribe((event: DragEvent) => {
|
||||
if (!this.isFileDrag(event.dataTransfer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event && event.pageX === 0 && event.pageY === 0) {
|
||||
this.fileDragLeave.emit();
|
||||
this.dragOver = false;
|
||||
if (!!this.fileUploadQueue) {
|
||||
this.fileUploadQueue.onDragLeave();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
fromEvent(window, 'drop')
|
||||
.pipe(takeUntil(this.ngOnDestroySubject))
|
||||
.subscribe((event: any) => {
|
||||
if (!this.isFileDrag(event.dataTransfer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const self = this;
|
||||
const files: FileList = event.dataTransfer.files;
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.elementRef.nativeElement.value = ''; // Case defined directive in 'input' type.
|
||||
this.dragOver = false;
|
||||
|
||||
if (!!this.validator) {
|
||||
this.validator(files)
|
||||
.then(async (result) => {
|
||||
if (!result) {
|
||||
if (!!this.fileUploadQueue) {
|
||||
this.fileUploadQueue.onUploadComplete();
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
const fileUploadItems = FileUploadItem.fromFiles(files);
|
||||
self.fileSelected.emit(fileUploadItems);
|
||||
|
||||
if (!!self.fileUploadQueue) {
|
||||
self.fileUploadQueue.onDrop(fileUploadItems);
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
if (!!this.fileUploadQueue) {
|
||||
this.fileUploadQueue.onUploadComplete();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
const fileUploadItems = FileUploadItem.fromFiles(files);
|
||||
this.fileSelected.emit(files);
|
||||
|
||||
if (!!this.fileUploadQueue) {
|
||||
this.fileUploadQueue.onDrop(fileUploadItems);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (!!this.ngOnDestroySubject) {
|
||||
this.ngOnDestroySubject.next();
|
||||
this.ngOnDestroySubject.complete();
|
||||
}
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {}
|
||||
|
||||
// @HostListener('change')
|
||||
// public onChange(): any {
|
||||
// const files = this.elementRef.nativeElement.files;
|
||||
// this.fileSelected.emit(FileUploadItem.fromFiles(files));
|
||||
// this.elementRef.nativeElement.value = '';
|
||||
// }
|
||||
|
||||
private isFileDrag(dataTransfer: DataTransfer): boolean {
|
||||
if (0 >= dataTransfer.items.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// tslint:disable-next-line: prefer-for-of
|
||||
for (let i = 0; i < dataTransfer.items.length; i++) {
|
||||
const element = dataTransfer.items[i];
|
||||
if ('file' !== element.kind) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user