0710 sync
This commit is contained in:
parent
92da6c71ce
commit
98ff58c39e
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
|
@ -12,5 +12,5 @@
|
||||||
},
|
},
|
||||||
"go.testFlags": ["-v"],
|
"go.testFlags": ["-v"],
|
||||||
"go.testTimeout": "100s",
|
"go.testTimeout": "100s",
|
||||||
"debug.node.autoAttach": "off"
|
"debug.node.autoAttach": "on"
|
||||||
}
|
}
|
||||||
|
|
41
angular.json
41
angular.json
|
@ -37,6 +37,10 @@
|
||||||
{
|
{
|
||||||
"replace": "src/environments/environment.ts",
|
"replace": "src/environments/environment.ts",
|
||||||
"with": "src/environments/environment.prod.ts"
|
"with": "src/environments/environment.prod.ts"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"replace": "src/environments/native/native.ts",
|
||||||
|
"with": "src/environments/native/native.browser.prod.ts"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"optimization": true,
|
"optimization": true,
|
||||||
|
@ -51,7 +55,7 @@
|
||||||
{
|
{
|
||||||
"type": "initial",
|
"type": "initial",
|
||||||
"maximumWarning": "2mb",
|
"maximumWarning": "2mb",
|
||||||
"maximumError": "5mb"
|
"maximumError": "6mb"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "anyComponentStyle",
|
"type": "anyComponentStyle",
|
||||||
|
@ -60,16 +64,19 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"production-es5": {
|
"production-renderer": {
|
||||||
"fileReplacements": [
|
"fileReplacements": [
|
||||||
{
|
{
|
||||||
"replace": "src/environments/environment.ts",
|
"replace": "src/environments/environment.ts",
|
||||||
"with": "src/environments/environment.prod.ts"
|
"with": "src/environments/environment.prod.ts"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"replace": "src/environments/native/native.ts",
|
||||||
|
"with": "src/environments/native/native.renderer.prod.ts"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"es5BrowserSupport": true,
|
"outputPath": "dist/ucap-lg-renderer",
|
||||||
"outputPath": "dist/ucap-lg-web-es5",
|
"tsConfig": "tsconfig.app.renderer.json",
|
||||||
"tsConfig": "tsconfig.app.es5.json",
|
|
||||||
"optimization": true,
|
"optimization": true,
|
||||||
"outputHashing": "all",
|
"outputHashing": "all",
|
||||||
"sourceMap": false,
|
"sourceMap": false,
|
||||||
|
@ -82,7 +89,7 @@
|
||||||
{
|
{
|
||||||
"type": "initial",
|
"type": "initial",
|
||||||
"maximumWarning": "2mb",
|
"maximumWarning": "2mb",
|
||||||
"maximumError": "5mb"
|
"maximumError": "6mb"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "anyComponentStyle",
|
"type": "anyComponentStyle",
|
||||||
|
@ -96,18 +103,26 @@
|
||||||
{
|
{
|
||||||
"replace": "src/environments/environment.ts",
|
"replace": "src/environments/environment.ts",
|
||||||
"with": "src/environments/environment.hmr.ts"
|
"with": "src/environments/environment.hmr.ts"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"replace": "src/environments/native/native.ts",
|
||||||
|
"with": "src/environments/native/native.browser.ts"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"hmr-es5": {
|
"hmr-renderer": {
|
||||||
"fileReplacements": [
|
"fileReplacements": [
|
||||||
{
|
{
|
||||||
"replace": "src/environments/environment.ts",
|
"replace": "src/environments/environment.ts",
|
||||||
"with": "src/environments/environment.hmr.ts"
|
"with": "src/environments/environment.hmr.ts"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"replace": "src/environments/native/native.ts",
|
||||||
|
"with": "src/environments/native/native.renderer.ts"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"es5BrowserSupport": true,
|
"es5BrowserSupport": false,
|
||||||
"tsConfig": "tsconfig.app.es5.json"
|
"tsConfig": "tsconfig.app.renderer.json"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -121,16 +136,16 @@
|
||||||
"production": {
|
"production": {
|
||||||
"browserTarget": "ucap-lg-web:build:production"
|
"browserTarget": "ucap-lg-web:build:production"
|
||||||
},
|
},
|
||||||
"production-5": {
|
"production-renderer": {
|
||||||
"browserTarget": "ucap-lg-web:build:production-es5"
|
"browserTarget": "ucap-lg-web:build:production-renderer"
|
||||||
},
|
},
|
||||||
"hmr": {
|
"hmr": {
|
||||||
"hmr": true,
|
"hmr": true,
|
||||||
"browserTarget": "ucap-lg-web:build:hmr"
|
"browserTarget": "ucap-lg-web:build:hmr"
|
||||||
},
|
},
|
||||||
"hmr-es5": {
|
"hmr-renderer": {
|
||||||
"hmr": true,
|
"hmr": true,
|
||||||
"browserTarget": "ucap-lg-web:build:hmr-es5"
|
"browserTarget": "ucap-lg-web:build:hmr-renderer"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,13 +1,20 @@
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
module.exports = (config, options) => {
|
module.exports = (config, options) => {
|
||||||
const PRODUCTION = process.env.NODE_ENV === 'production';
|
const PRODUCTION =
|
||||||
|
!!process.env.NODE_ENV && 'production' === process.env.NODE_ENV;
|
||||||
|
const RENDERER =
|
||||||
|
!!process.env.NATIVE_ENV && 'renderer' === process.env.NATIVE_ENV;
|
||||||
|
|
||||||
config.target = 'web';
|
if (RENDERER) {
|
||||||
config.node = {
|
config.target = 'electron-renderer';
|
||||||
global: true,
|
} else {
|
||||||
fs: 'empty'
|
config.target = 'web';
|
||||||
};
|
config.node = {
|
||||||
|
global: true,
|
||||||
|
fs: 'empty'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
config.resolve.alias = {
|
config.resolve.alias = {
|
||||||
...config.resolve.alias,
|
...config.resolve.alias,
|
||||||
|
|
1175
package-lock.json
generated
1175
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
95
package.json
95
package.json
|
@ -5,42 +5,41 @@
|
||||||
"ng": "ng",
|
"ng": "ng",
|
||||||
"start": "ng serve",
|
"start": "ng serve",
|
||||||
"start:hmr": "ng serve --configuration hmr",
|
"start:hmr": "ng serve --configuration hmr",
|
||||||
"start:hmr-es5": "ng serve --configuration hmr-es5",
|
"start:hmr-renderer": "ng serve --configuration hmr-renderer",
|
||||||
"build": "ng build",
|
"build": "ng build",
|
||||||
"build:production": "ng build --prod",
|
"build:production": "ng build --prod",
|
||||||
"build:production-es5": "ng build --configuration production-es5",
|
"build:production-renderer": "cross-env NATIVE_ENV=renderer ng build --prod --configuration production-renderer --base-href ./",
|
||||||
"test": "ng test",
|
"test": "ng test",
|
||||||
"lint": "ng lint",
|
"lint": "ng lint",
|
||||||
"e2e": "ng e2e"
|
"e2e": "ng e2e"
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/animations": "~9.0.6",
|
"@angular/animations": "^9.1.11",
|
||||||
"@angular/cdk": "^9.1.3",
|
"@angular/cdk": "^9.2.4",
|
||||||
"@angular/common": "~9.0.6",
|
"@angular/common": "^9.1.11",
|
||||||
"@angular/compiler": "~9.0.6",
|
"@angular/compiler": "^9.1.11",
|
||||||
"@angular/core": "~9.0.6",
|
"@angular/core": "^9.1.11",
|
||||||
"@angular/flex-layout": "^9.0.0-beta.29",
|
"@angular/flex-layout": "^9.0.0-beta.31",
|
||||||
"@angular/forms": "~9.0.6",
|
"@angular/forms": "^9.1.11",
|
||||||
"@angular/material": "^9.1.3",
|
"@angular/material": "^9.2.4",
|
||||||
"@angular/material-moment-adapter": "^9.1.3",
|
"@angular/material-moment-adapter": "^9.2.4",
|
||||||
"@angular/platform-browser": "~9.0.6",
|
"@angular/platform-browser": "^9.1.11",
|
||||||
"@angular/platform-browser-dynamic": "~9.0.6",
|
"@angular/platform-browser-dynamic": "^9.1.11",
|
||||||
"@angular/router": "~9.0.6",
|
"@angular/router": "^9.1.11",
|
||||||
"@ngrx/effects": "^9.0.0",
|
"@ngrx/effects": "^9.2.0",
|
||||||
"@ngrx/entity": "^9.0.0",
|
"@ngrx/entity": "^9.2.0",
|
||||||
"@ngrx/router-store": "^9.0.0",
|
"@ngrx/router-store": "^9.2.0",
|
||||||
"@ngrx/store": "^9.0.0",
|
"@ngrx/store": "^9.2.0",
|
||||||
"@ucap/api": "~0.0.2",
|
"@ucap/api": "~0.0.4",
|
||||||
"@ucap/api-common": "~0.0.5",
|
"@ucap/api-common": "~0.0.11",
|
||||||
"@ucap/api-external": "~0.0.5",
|
"@ucap/api-external": "~0.0.5",
|
||||||
"@ucap/api-message": "~0.0.3",
|
"@ucap/api-message": "~0.0.3",
|
||||||
"@ucap/api-prompt": "~0.0.3",
|
"@ucap/api-prompt": "~0.0.3",
|
||||||
"@ucap/api-public": "~0.0.4",
|
"@ucap/api-public": "~0.0.4",
|
||||||
"@ucap/core": "~0.0.10",
|
"@ucap/core": "~0.0.14",
|
||||||
"@ucap/logger": "~0.0.12",
|
"@ucap/logger": "~0.0.13",
|
||||||
"@ucap/native": "~0.0.6",
|
"@ucap/native": "~0.0.19",
|
||||||
"@ucap/native-browser": "~0.0.5",
|
|
||||||
"@ucap/ng-api-common": "~0.0.1",
|
"@ucap/ng-api-common": "~0.0.1",
|
||||||
"@ucap/ng-api-external": "~0.0.1",
|
"@ucap/ng-api-external": "~0.0.1",
|
||||||
"@ucap/ng-api-message": "~0.0.1",
|
"@ucap/ng-api-message": "~0.0.1",
|
||||||
|
@ -49,8 +48,7 @@
|
||||||
"@ucap/ng-core": "~0.0.7",
|
"@ucap/ng-core": "~0.0.7",
|
||||||
"@ucap/ng-logger": "~0.0.2",
|
"@ucap/ng-logger": "~0.0.2",
|
||||||
"@ucap/ng-i18n": "~0.0.6",
|
"@ucap/ng-i18n": "~0.0.6",
|
||||||
"@ucap/ng-native": "~0.0.1",
|
"@ucap/ng-native": "~0.0.5",
|
||||||
"@ucap/ng-native-browser": "~0.0.1",
|
|
||||||
"@ucap/ng-pi": "~0.0.1",
|
"@ucap/ng-pi": "~0.0.1",
|
||||||
"@ucap/ng-protocol": "~0.0.3",
|
"@ucap/ng-protocol": "~0.0.3",
|
||||||
"@ucap/ng-protocol-authentication": "~0.0.3",
|
"@ucap/ng-protocol-authentication": "~0.0.3",
|
||||||
|
@ -68,35 +66,35 @@
|
||||||
"@ucap/ng-protocol-status": "~0.0.3",
|
"@ucap/ng-protocol-status": "~0.0.3",
|
||||||
"@ucap/ng-protocol-sync": "~0.0.3",
|
"@ucap/ng-protocol-sync": "~0.0.3",
|
||||||
"@ucap/ng-protocol-umg": "~0.0.3",
|
"@ucap/ng-protocol-umg": "~0.0.3",
|
||||||
"@ucap/ng-store-authentication": "~0.0.11",
|
"@ucap/ng-store-authentication": "~0.0.14",
|
||||||
"@ucap/ng-store-chat": "~0.0.16",
|
"@ucap/ng-store-chat": "~0.0.66",
|
||||||
"@ucap/ng-store-group": "~0.0.14",
|
"@ucap/ng-store-group": "~0.0.22",
|
||||||
"@ucap/ng-store-organization": "~0.0.8",
|
"@ucap/ng-store-organization": "~0.0.20",
|
||||||
"@ucap/ng-web-socket": "~0.0.2",
|
"@ucap/ng-web-socket": "~0.0.2",
|
||||||
"@ucap/ng-web-storage": "~0.0.3",
|
"@ucap/ng-web-storage": "~0.0.3",
|
||||||
"@ucap/ng-ui": "~0.0.19",
|
"@ucap/ng-ui": "0.0.97",
|
||||||
"@ucap/ng-ui-organization": "~0.0.83",
|
"@ucap/ng-ui-organization": "~0.0.202",
|
||||||
"@ucap/ng-ui-authentication": "~0.0.25",
|
"@ucap/ng-ui-authentication": "~0.0.29",
|
||||||
"@ucap/ng-ui-group": "~0.0.33",
|
"@ucap/ng-ui-group": "~0.0.78",
|
||||||
"@ucap/ng-ui-chat": "~0.0.12",
|
"@ucap/ng-ui-chat": "~0.0.72",
|
||||||
"@ucap/ng-ui-material": "~0.0.4",
|
"@ucap/ng-ui-material": "~0.0.4",
|
||||||
"@ucap/ng-ui-skin-default": "~0.0.1",
|
"@ucap/ng-ui-skin-default": "~0.0.1",
|
||||||
"@ucap/pi": "~0.0.5",
|
"@ucap/pi": "~0.0.8",
|
||||||
"@ucap/protocol": "~0.0.17",
|
"@ucap/protocol": "~0.0.17",
|
||||||
"@ucap/protocol-authentication": "~0.0.5",
|
"@ucap/protocol-authentication": "~0.0.5",
|
||||||
"@ucap/protocol-buddy": "~0.0.5",
|
"@ucap/protocol-buddy": "~0.0.5",
|
||||||
"@ucap/protocol-event": "~0.0.5",
|
"@ucap/protocol-event": "~0.0.6",
|
||||||
"@ucap/protocol-file": "~0.0.4",
|
"@ucap/protocol-file": "~0.0.6",
|
||||||
"@ucap/protocol-group": "~0.0.5",
|
"@ucap/protocol-group": "~0.0.5",
|
||||||
"@ucap/protocol-info": "~0.0.6",
|
"@ucap/protocol-info": "~0.0.9",
|
||||||
"@ucap/protocol-inner": "~0.0.4",
|
"@ucap/protocol-inner": "~0.0.4",
|
||||||
"@ucap/protocol-option": "~0.0.7",
|
"@ucap/protocol-option": "~0.0.7",
|
||||||
"@ucap/protocol-ping": "~0.0.6",
|
"@ucap/protocol-ping": "~0.0.6",
|
||||||
"@ucap/protocol-query": "~0.0.5",
|
"@ucap/protocol-query": "~0.0.5",
|
||||||
"@ucap/protocol-room": "~0.0.6",
|
"@ucap/protocol-room": "~0.0.7",
|
||||||
"@ucap/protocol-service": "~0.0.4",
|
"@ucap/protocol-service": "~0.0.4",
|
||||||
"@ucap/protocol-status": "~0.0.5",
|
"@ucap/protocol-status": "~0.0.5",
|
||||||
"@ucap/protocol-sync": "~0.0.4",
|
"@ucap/protocol-sync": "~0.0.6",
|
||||||
"@ucap/protocol-umg": "~0.0.5",
|
"@ucap/protocol-umg": "~0.0.5",
|
||||||
"@ucap/ui-scss": "~0.0.5",
|
"@ucap/ui-scss": "~0.0.5",
|
||||||
"@ucap/web-socket": "~0.0.10",
|
"@ucap/web-socket": "~0.0.10",
|
||||||
|
@ -109,13 +107,13 @@
|
||||||
"file-type": "^14.1.4",
|
"file-type": "^14.1.4",
|
||||||
"i18next": "^19.3.3",
|
"i18next": "^19.3.3",
|
||||||
"i18next-browser-languagedetector": "^4.0.2",
|
"i18next-browser-languagedetector": "^4.0.2",
|
||||||
"i18next-node-fs-backend": "^2.1.3",
|
"i18next-fs-backend": "^1.0.6",
|
||||||
"i18next-xhr-backend": "^3.2.2",
|
"i18next-xhr-backend": "^3.2.2",
|
||||||
"libphonenumber-js": "^1.7.47",
|
"libphonenumber-js": "^1.7.47",
|
||||||
|
"memoize-one": "^5.1.1",
|
||||||
"moment": "^2.24.0",
|
"moment": "^2.24.0",
|
||||||
"moment-timezone": "^0.5.28",
|
"moment-timezone": "^0.5.28",
|
||||||
"ngx-perfect-scrollbar": "^9.0.0",
|
"ngx-perfect-scrollbar": "^9.0.0",
|
||||||
"ngx-virtual-scroller": "^4.0.3",
|
|
||||||
"pino": "^6.0.0",
|
"pino": "^6.0.0",
|
||||||
"queueing-subject": "^0.3.4",
|
"queueing-subject": "^0.3.4",
|
||||||
"rxjs": "~6.5.4",
|
"rxjs": "~6.5.4",
|
||||||
|
@ -126,16 +124,16 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular-builders/custom-webpack": "^9.0.0",
|
"@angular-builders/custom-webpack": "^9.0.0",
|
||||||
"@angular-devkit/build-angular": "~0.900.6",
|
"@angular-devkit/build-angular": "~0.900.6",
|
||||||
"@angular/cli": "~9.0.6",
|
"@angular/cli": "^9.1.9",
|
||||||
"@angular/compiler-cli": "~9.0.6",
|
"@angular/compiler-cli": "^9.1.11",
|
||||||
"@angular/language-service": "~9.0.6",
|
"@angular/language-service": "^9.1.11",
|
||||||
"@angularclass/hmr": "^2.1.3",
|
"@angularclass/hmr": "^2.1.3",
|
||||||
"@ngrx/store-devtools": "^9.0.0",
|
"@ngrx/store-devtools": "^9.0.0",
|
||||||
"@types/i18next-node-fs-backend": "^2.1.0",
|
|
||||||
"@types/jasmine": "~3.5.0",
|
"@types/jasmine": "~3.5.0",
|
||||||
"@types/jasminewd2": "~2.0.3",
|
"@types/jasminewd2": "~2.0.3",
|
||||||
"@types/node": "^12.11.1",
|
"@types/node": "^12.11.1",
|
||||||
"codelyzer": "^5.1.2",
|
"codelyzer": "^5.1.2",
|
||||||
|
"cross-env": "^7.0.2",
|
||||||
"fs-extra": "^9.0.0",
|
"fs-extra": "^9.0.0",
|
||||||
"jasmine-core": "~3.5.0",
|
"jasmine-core": "~3.5.0",
|
||||||
"jasmine-spec-reporter": "~4.2.1",
|
"jasmine-spec-reporter": "~4.2.1",
|
||||||
|
@ -148,6 +146,7 @@
|
||||||
"ts-node": "~8.3.0",
|
"ts-node": "~8.3.0",
|
||||||
"tslint": "~5.18.0",
|
"tslint": "~5.18.0",
|
||||||
"typescript": "~3.7.5",
|
"typescript": "~3.7.5",
|
||||||
"webpack-bundle-analyzer": "^3.7.0"
|
"webpack-bundle-analyzer": "^3.7.0",
|
||||||
|
"webpack-node-externals": "^1.7.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,10 +12,13 @@ import { AppAuthenticationGuard } from './guards/app-authentication.guard';
|
||||||
import { AppSessionResolver } from './resolvers/app-session.resolver';
|
import { AppSessionResolver } from './resolvers/app-session.resolver';
|
||||||
|
|
||||||
import { AppAuthenticationService } from './services/app-authentication.service';
|
import { AppAuthenticationService } from './services/app-authentication.service';
|
||||||
|
import { AppNotificationService } from './services/app-notification.service';
|
||||||
import { AppNativeService } from './services/app-native.service';
|
import { AppNativeService } from './services/app-native.service';
|
||||||
import { AppService } from './services/app.service';
|
import { AppService } from './services/app.service';
|
||||||
import { AppChatService } from './services/app-chat.service';
|
import { AppChatService } from './services/app-chat.service';
|
||||||
import { AppFileService } from './services/app-file.service';
|
import { AppFileService } from './services/app-file.service';
|
||||||
|
import { AppGroupService } from './services/app-group.service';
|
||||||
|
import { AppAccountService } from './services/app-account.service';
|
||||||
|
|
||||||
const GUARDS = [AppAuthenticationGuard];
|
const GUARDS = [AppAuthenticationGuard];
|
||||||
const RESOLVERS = [AppSessionResolver];
|
const RESOLVERS = [AppSessionResolver];
|
||||||
|
@ -24,7 +27,10 @@ const SERVICES = [
|
||||||
AppAuthenticationService,
|
AppAuthenticationService,
|
||||||
AppNativeService,
|
AppNativeService,
|
||||||
AppFileService,
|
AppFileService,
|
||||||
AppChatService
|
AppChatService,
|
||||||
|
AppNotificationService,
|
||||||
|
AppGroupService,
|
||||||
|
AppAccountService
|
||||||
];
|
];
|
||||||
|
|
||||||
const axiosFactory = () => {
|
const axiosFactory = () => {
|
||||||
|
@ -35,6 +41,9 @@ const axiosFactory = () => {
|
||||||
return i;
|
return i;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const nativeServiceFactory = (nativeService: any) =>
|
||||||
|
new environment.productConfig.nativeServiceClass(nativeService);
|
||||||
|
|
||||||
const appInit = (appService: AppService) => {
|
const appInit = (appService: AppService) => {
|
||||||
return () => appService.initialize();
|
return () => appService.initialize();
|
||||||
};
|
};
|
||||||
|
@ -51,7 +60,7 @@ const appInit = (appService: AppService) => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: UCAP_NATIVE_SERVICE,
|
provide: UCAP_NATIVE_SERVICE,
|
||||||
useClass: environment.productConfig.nativeServiceClass,
|
useFactory: nativeServiceFactory,
|
||||||
deps: [AXIOS_INSTANCE],
|
deps: [AXIOS_INSTANCE],
|
||||||
multi: false
|
multi: false
|
||||||
},
|
},
|
||||||
|
|
|
@ -81,7 +81,9 @@ const routes: Routes = [
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [RouterModule.forRoot(routes)],
|
imports: [
|
||||||
|
RouterModule.forRoot(routes, { useHash: true, enableTracing: false })
|
||||||
|
],
|
||||||
exports: [RouterModule]
|
exports: [RouterModule]
|
||||||
})
|
})
|
||||||
export class AppRoutingModule {}
|
export class AppRoutingModule {}
|
||||||
|
|
|
@ -1,28 +1,48 @@
|
||||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
import {
|
||||||
|
Component,
|
||||||
|
OnDestroy,
|
||||||
|
OnInit,
|
||||||
|
AfterViewInit,
|
||||||
|
Renderer2
|
||||||
|
} from '@angular/core';
|
||||||
|
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
|
|
||||||
import { AppActions } from '@app/store/actions';
|
import { AppActions } from '@app/store/actions';
|
||||||
import { fromEvent, interval, Subscription } from 'rxjs';
|
import { fromEvent, interval, Subject } from 'rxjs';
|
||||||
import { debounce } from 'rxjs/operators';
|
import { debounce, takeUntil } from 'rxjs/operators';
|
||||||
|
import { AppAuthenticationService } from './services/app-authentication.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
templateUrl: './app.component.html',
|
templateUrl: './app.component.html',
|
||||||
styleUrls: ['./app.component.scss']
|
styleUrls: ['./app.component.scss']
|
||||||
})
|
})
|
||||||
export class AppComponent implements OnInit, OnDestroy {
|
export class AppComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
private resizeWindowSubscription: Subscription;
|
private ngOnDestroySubject: Subject<void> = new Subject();
|
||||||
|
|
||||||
constructor(private store: Store<any>) {
|
constructor(
|
||||||
this.resizeWindowSubscription = fromEvent(window, 'resize')
|
private renderer2: Renderer2,
|
||||||
.pipe(debounce(() => interval(100)))
|
private store: Store<any>,
|
||||||
|
private appAuthenticationService: AppAuthenticationService
|
||||||
|
) {
|
||||||
|
fromEvent(window, 'resize')
|
||||||
|
.pipe(
|
||||||
|
takeUntil(this.ngOnDestroySubject),
|
||||||
|
debounce(() => interval(100))
|
||||||
|
)
|
||||||
.subscribe((event: any) => {
|
.subscribe((event: any) => {
|
||||||
this.dispatchWindowSize({
|
this.dispatchWindowSize({
|
||||||
width: event.target.innerWidth,
|
width: event.target.innerWidth,
|
||||||
height: event.target.innerHeight
|
height: event.target.innerHeight
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// fromEvent(window, 'beforeunload')
|
||||||
|
// .pipe(takeUntil(this.ngOnDestroySubject))
|
||||||
|
// .subscribe((event: any) => {
|
||||||
|
// this.appAuthenticationService.logout();
|
||||||
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
@ -33,11 +53,19 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
if (!!this.resizeWindowSubscription) {
|
if (!!this.ngOnDestroySubject) {
|
||||||
this.resizeWindowSubscription.unsubscribe();
|
this.ngOnDestroySubject.next();
|
||||||
|
this.ngOnDestroySubject.complete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngAfterViewInit(): void {
|
||||||
|
const preloader = this.renderer2.selectRootElement(
|
||||||
|
'#ucap-lg-web-preloader'
|
||||||
|
);
|
||||||
|
this.renderer2.setStyle(preloader, 'display', 'none');
|
||||||
|
}
|
||||||
|
|
||||||
private dispatchWindowSize(size: { width: number; height: number }) {
|
private dispatchWindowSize(size: { width: number; height: number }) {
|
||||||
this.store.dispatch(AppActions.windowResized(size));
|
this.store.dispatch(AppActions.windowResized(size));
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,8 @@ import { effects } from '@app/store/effects';
|
||||||
import { ROOT_REDUCERS } from '@app/store/reducers';
|
import { ROOT_REDUCERS } from '@app/store/reducers';
|
||||||
import { metaReducers } from '@app/store/state';
|
import { metaReducers } from '@app/store/state';
|
||||||
|
|
||||||
|
import { AppAccountDialogModule } from '@app/dialogs/account/account.dialog.module';
|
||||||
|
|
||||||
import { environment } from '@environments';
|
import { environment } from '@environments';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
@ -69,6 +71,56 @@ import { environment } from '@environments';
|
||||||
|
|
||||||
FlexLayoutModule,
|
FlexLayoutModule,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StoreModule.forRoot is imported once in the root module, accepting a reducer
|
||||||
|
* function or object map of reducer functions. If passed an object of
|
||||||
|
* reducers, combineReducers will be run creating your application
|
||||||
|
* meta-reducer. This returns all providers for an @ngrx/store
|
||||||
|
* based application.
|
||||||
|
*/
|
||||||
|
StoreModule.forRoot(ROOT_REDUCERS, {
|
||||||
|
metaReducers,
|
||||||
|
runtimeChecks: {
|
||||||
|
strictStateImmutability: true,
|
||||||
|
strictActionImmutability: true,
|
||||||
|
strictStateSerializability: true,
|
||||||
|
strictActionSerializability: true
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ngrx/router-store keeps router state up-to-date in the store.
|
||||||
|
*/
|
||||||
|
StoreRouterConnectingModule.forRoot({
|
||||||
|
routerState: RouterState.Minimal
|
||||||
|
}),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store devtools instrument the store retaining past versions of state
|
||||||
|
* and recalculating new states. This enables powerful time-travel
|
||||||
|
* debugging.
|
||||||
|
*
|
||||||
|
* To use the debugger, install the Redux Devtools extension for either
|
||||||
|
* Chrome or Firefox
|
||||||
|
*
|
||||||
|
* See: https://github.com/zalmoxisus/redux-devtools-extension
|
||||||
|
*/
|
||||||
|
StoreDevtoolsModule.instrument({
|
||||||
|
name: 'UCAP Store App'
|
||||||
|
|
||||||
|
// In a production build you would want to disable the Store Devtools
|
||||||
|
// logOnly: environment.production,
|
||||||
|
}),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EffectsModule.forRoot() is imported once in the root module and
|
||||||
|
* sets up the effects class to be initialized immediately when the
|
||||||
|
* application starts.
|
||||||
|
*
|
||||||
|
* See: https://ngrx.io/guide/effects#registering-root-effects
|
||||||
|
*/
|
||||||
|
EffectsModule.forRoot([...effects]),
|
||||||
|
|
||||||
LoggerModule.forRoot({}),
|
LoggerModule.forRoot({}),
|
||||||
|
|
||||||
CommonApiModule.forRoot(environment.commonApiModuleConfig),
|
CommonApiModule.forRoot(environment.commonApiModuleConfig),
|
||||||
|
@ -118,55 +170,7 @@ import { environment } from '@environments';
|
||||||
|
|
||||||
AppLayoutsModule,
|
AppLayoutsModule,
|
||||||
|
|
||||||
/**
|
AppAccountDialogModule
|
||||||
* StoreModule.forRoot is imported once in the root module, accepting a reducer
|
|
||||||
* function or object map of reducer functions. If passed an object of
|
|
||||||
* reducers, combineReducers will be run creating your application
|
|
||||||
* meta-reducer. This returns all providers for an @ngrx/store
|
|
||||||
* based application.
|
|
||||||
*/
|
|
||||||
StoreModule.forRoot(ROOT_REDUCERS, {
|
|
||||||
metaReducers,
|
|
||||||
runtimeChecks: {
|
|
||||||
strictStateImmutability: true,
|
|
||||||
strictActionImmutability: true,
|
|
||||||
strictStateSerializability: true,
|
|
||||||
strictActionSerializability: true
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngrx/router-store keeps router state up-to-date in the store.
|
|
||||||
*/
|
|
||||||
StoreRouterConnectingModule.forRoot({
|
|
||||||
routerState: RouterState.Minimal
|
|
||||||
}),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store devtools instrument the store retaining past versions of state
|
|
||||||
* and recalculating new states. This enables powerful time-travel
|
|
||||||
* debugging.
|
|
||||||
*
|
|
||||||
* To use the debugger, install the Redux Devtools extension for either
|
|
||||||
* Chrome or Firefox
|
|
||||||
*
|
|
||||||
* See: https://github.com/zalmoxisus/redux-devtools-extension
|
|
||||||
*/
|
|
||||||
StoreDevtoolsModule.instrument({
|
|
||||||
name: 'UCAP Store App'
|
|
||||||
|
|
||||||
// In a production build you would want to disable the Store Devtools
|
|
||||||
// logOnly: environment.production,
|
|
||||||
}),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* EffectsModule.forRoot() is imported once in the root module and
|
|
||||||
* sets up the effects class to be initialized immediately when the
|
|
||||||
* application starts.
|
|
||||||
*
|
|
||||||
* See: https://ngrx.io/guide/effects#registering-root-effects
|
|
||||||
*/
|
|
||||||
EffectsModule.forRoot([...effects])
|
|
||||||
],
|
],
|
||||||
providers: [],
|
providers: [],
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
|
|
|
@ -22,7 +22,7 @@ $typography: mat-typography-config(
|
||||||
// Define the palettes for your theme using the Material Design palettes available in palette.scss
|
// Define the palettes for your theme using the Material Design palettes available in palette.scss
|
||||||
// (imported above). For each palette, you can optionally specify a default, lighter, and darker
|
// (imported above). For each palette, you can optionally specify a default, lighter, and darker
|
||||||
// hue. Available color palettes: https://material.io/design/color/
|
// hue. Available color palettes: https://material.io/design/color/
|
||||||
$lgRed-app-primary: mat-palette($ucap-color-primary);
|
$lgRed-app-primary: mat-palette($ucap-color-primary, 600);
|
||||||
$lgRed-app-accent: mat-palette($ucap-color-accent, 700);
|
$lgRed-app-accent: mat-palette($ucap-color-accent, 700);
|
||||||
|
|
||||||
// The warn palette is optional (defaults to red).
|
// The warn palette is optional (defaults to red).
|
||||||
|
|
48
src/app/dialogs/account/account.dialog.module.ts
Normal file
48
src/app/dialogs/account/account.dialog.module.ts
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { ReactiveFormsModule } from '@angular/forms';
|
||||||
|
|
||||||
|
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||||
|
|
||||||
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||||
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
|
import { MatInputModule } from '@angular/material/input';
|
||||||
|
import { MatRadioModule } from '@angular/material/radio';
|
||||||
|
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 { AppLayoutsModule } from '@app/layouts/layouts.module';
|
||||||
|
import { AppAccountSectionModule } from '@app/sections/account/account.section.module';
|
||||||
|
|
||||||
|
import { COMPONENTS } from './components';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
FlexLayoutModule,
|
||||||
|
|
||||||
|
MatButtonModule,
|
||||||
|
MatCheckboxModule,
|
||||||
|
MatIconModule,
|
||||||
|
MatInputModule,
|
||||||
|
MatRadioModule,
|
||||||
|
MatSelectModule,
|
||||||
|
MatTabsModule,
|
||||||
|
|
||||||
|
I18nModule,
|
||||||
|
|
||||||
|
UiModule,
|
||||||
|
|
||||||
|
AppLayoutsModule,
|
||||||
|
AppAccountSectionModule
|
||||||
|
],
|
||||||
|
exports: [...COMPONENTS],
|
||||||
|
declarations: [...COMPONENTS],
|
||||||
|
entryComponents: [...COMPONENTS]
|
||||||
|
})
|
||||||
|
export class AppAccountDialogModule {}
|
3
src/app/dialogs/account/components/index.ts
Normal file
3
src/app/dialogs/account/components/index.ts
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
import { SettingsDialogComponent } from './settings.dialog.component';
|
||||||
|
|
||||||
|
export const COMPONENTS = [SettingsDialogComponent];
|
|
@ -0,0 +1,471 @@
|
||||||
|
<div class="dialog-container">
|
||||||
|
<app-layouts-default-dialog
|
||||||
|
[disableClose]="false"
|
||||||
|
(closed)="onClosed($event)"
|
||||||
|
class="create-dialog-container"
|
||||||
|
>
|
||||||
|
<div appLayoutsDefaultDialog="header">
|
||||||
|
{{ 'organization:settings.label' | ucapI18n }}
|
||||||
|
</div>
|
||||||
|
<div class="dialog-body" appLayoutsDefaultDialog="body">
|
||||||
|
<mat-tab-group mat-stretch-tabs>
|
||||||
|
<mat-tab>
|
||||||
|
<ng-template mat-tab-label>
|
||||||
|
<p>{{ 'organization:settings.sub.general' | ucapI18n }}</p>
|
||||||
|
</ng-template>
|
||||||
|
<div class="default-settings-area">
|
||||||
|
<!-- 기본설정 -->
|
||||||
|
<div
|
||||||
|
*ngIf="'electron' === platform"
|
||||||
|
class="messenger-settings-area login-setting-box"
|
||||||
|
>
|
||||||
|
<div class="title-settings-subject">
|
||||||
|
<span>{{
|
||||||
|
'authentication:login.settings.login' | ucapI18n
|
||||||
|
}}</span>
|
||||||
|
<button mat-icon-button color="accent" class="btn-subject-info">
|
||||||
|
<mat-icon>info_outline</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="settings-contents">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<mat-checkbox>
|
||||||
|
{{
|
||||||
|
'authentication:login.settings.autoStartOnBoot'
|
||||||
|
| ucapI18n
|
||||||
|
}}
|
||||||
|
</mat-checkbox>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<mat-checkbox>
|
||||||
|
{{ 'authentication:login.settings.autoLogin' | ucapI18n }}
|
||||||
|
</mat-checkbox>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<mat-checkbox>
|
||||||
|
{{ 'authentication:login.settings.autoHide' | ucapI18n }}
|
||||||
|
</mat-checkbox>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="messenger-settings-area language-setting-box">
|
||||||
|
<div class="title-settings-subject">
|
||||||
|
<span>{{
|
||||||
|
'organization:settings.language.messenger' | ucapI18n
|
||||||
|
}}</span>
|
||||||
|
<button mat-icon-button color="accent" class="btn-subject-info">
|
||||||
|
<mat-icon>info_outline</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="settings-contents">
|
||||||
|
<mat-form-field
|
||||||
|
color="accent"
|
||||||
|
appearance="standard"
|
||||||
|
class="setting-select-obj ucap-mat-input-container"
|
||||||
|
>
|
||||||
|
<mat-select
|
||||||
|
[value]="generalSetting.locale"
|
||||||
|
(selectionChange)="onSelectionChangeLanguage($event)"
|
||||||
|
>
|
||||||
|
<mat-option
|
||||||
|
*ngFor="let languageCode of supportedLanguages"
|
||||||
|
[value]="languageCode"
|
||||||
|
>
|
||||||
|
{{ 'locale:languages.' + languageCode | ucapI18n }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="messenger-settings-area language-setting-box">
|
||||||
|
<div class="title-settings-subject">
|
||||||
|
<span>{{
|
||||||
|
'organization:settings.language.hr' | ucapI18n
|
||||||
|
}}</span>
|
||||||
|
<button mat-icon-button color="accent" class="btn-subject-info">
|
||||||
|
<mat-icon>info_outline</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="settings-contents">
|
||||||
|
<mat-form-field
|
||||||
|
color="accent"
|
||||||
|
appearance="standard"
|
||||||
|
class="setting-select-obj ucap-mat-input-container"
|
||||||
|
>
|
||||||
|
<mat-select
|
||||||
|
[value]="generalSetting.hrInfoLocale"
|
||||||
|
(selectionChange)="onSelectionChangeHrLanguage($event)"
|
||||||
|
>
|
||||||
|
<mat-option
|
||||||
|
*ngFor="let languageCode of supportedHrLanguages"
|
||||||
|
[value]="languageCode"
|
||||||
|
>
|
||||||
|
{{ 'locale:languages.' + languageCode | ucapI18n }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="messenger-settings-area time-setting-box">
|
||||||
|
<div class="title-settings-subject">
|
||||||
|
<span>{{ 'organization:settings.timezone' | ucapI18n }}</span>
|
||||||
|
<button mat-icon-button color="accent" class="btn-subject-info">
|
||||||
|
<mat-icon>info_outline</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="settings-contents">
|
||||||
|
<mat-form-field
|
||||||
|
color="accent"
|
||||||
|
appearance="standard"
|
||||||
|
class="setting-select-obj ucap-mat-input-container"
|
||||||
|
>
|
||||||
|
<mat-select
|
||||||
|
#selectForTimezone
|
||||||
|
[formControl]="formControlForTimezone"
|
||||||
|
[placeholder]="timezonePlaceholder"
|
||||||
|
[value]="generalSetting.timezone"
|
||||||
|
(openedChange)="onOpenedChangeTimezone($event)"
|
||||||
|
>
|
||||||
|
<ucap-virtual-scroll-viewport
|
||||||
|
class="general-timezone-viewport"
|
||||||
|
#vsTimezone
|
||||||
|
itemSize="48"
|
||||||
|
[style.height.px]="5 * 48"
|
||||||
|
>
|
||||||
|
<mat-option
|
||||||
|
*ucapVirtualFor="let timezone of timezoneList"
|
||||||
|
[value]="timezone.name"
|
||||||
|
(onSelectionChange)="onSelectionChangeTimezone($event)"
|
||||||
|
>
|
||||||
|
{{ timezone.displayName }}
|
||||||
|
</mat-option>
|
||||||
|
</ucap-virtual-scroll-viewport>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</mat-tab>
|
||||||
|
<mat-tab>
|
||||||
|
<ng-template mat-tab-label>
|
||||||
|
<p>{{ 'organization:settings.sub.notification' | ucapI18n }}</p>
|
||||||
|
</ng-template>
|
||||||
|
<div class="allim-settings-area">
|
||||||
|
<!-- 알림 -->
|
||||||
|
<div class="messenger-settings-area">
|
||||||
|
<div class="title-settings-subject">
|
||||||
|
{{ 'organization:settings.notification.receival' | ucapI18n }}
|
||||||
|
</div>
|
||||||
|
<div class="settings-contents">
|
||||||
|
<mat-radio-group
|
||||||
|
aria-label="Select an type of alarm"
|
||||||
|
class="settings-radio-group"
|
||||||
|
>
|
||||||
|
<mat-radio-button value="true">
|
||||||
|
{{
|
||||||
|
'organization:settings.notification.receive' | ucapI18n
|
||||||
|
}}
|
||||||
|
</mat-radio-button>
|
||||||
|
<mat-radio-button value="false">
|
||||||
|
{{
|
||||||
|
'organization:settings.notification.notReceive' | ucapI18n
|
||||||
|
}}
|
||||||
|
</mat-radio-button>
|
||||||
|
</mat-radio-group>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="messenger-settings-area allim-way-box">
|
||||||
|
<div class="title-settings-subject">
|
||||||
|
{{ 'organization:settings.notification.method' | ucapI18n }}
|
||||||
|
</div>
|
||||||
|
<div class="settings-contents">
|
||||||
|
<mat-form-field
|
||||||
|
color="accent"
|
||||||
|
appearance="standard"
|
||||||
|
class="setting-select-obj ucap-mat-input-container"
|
||||||
|
>
|
||||||
|
<mat-select>
|
||||||
|
<mat-option value="sound">
|
||||||
|
{{
|
||||||
|
'organization:settings.notification.methodTypeSound'
|
||||||
|
| ucapI18n
|
||||||
|
}}
|
||||||
|
</mat-option>
|
||||||
|
<mat-option value="alert">
|
||||||
|
{{
|
||||||
|
'organization:settings.notification.methodTypeAlert'
|
||||||
|
| ucapI18n
|
||||||
|
}}
|
||||||
|
</mat-option>
|
||||||
|
<mat-option value="soundAndAlert">
|
||||||
|
{{
|
||||||
|
'organization:settings.notification.methodTypeSoundAndAlert'
|
||||||
|
| ucapI18n
|
||||||
|
}}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="messenger-settings-area allim-time-box">
|
||||||
|
<div class="title-settings-subject">
|
||||||
|
{{
|
||||||
|
'organization:settings.notification.settingOfAlertWindow'
|
||||||
|
| ucapI18n
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
<div class="settings-contents">
|
||||||
|
<mat-form-field
|
||||||
|
color="accent"
|
||||||
|
appearance="standard"
|
||||||
|
class="setting-select-obj ucap-mat-input-container"
|
||||||
|
>
|
||||||
|
<mat-select>
|
||||||
|
<mat-option value="5">
|
||||||
|
5{{ 'common:units.second' | ucapI18n }}
|
||||||
|
</mat-option>
|
||||||
|
<mat-option value="10">
|
||||||
|
10{{ 'common:units.second' | ucapI18n }}
|
||||||
|
</mat-option>
|
||||||
|
<mat-option value="15">
|
||||||
|
15{{ 'common:units.second' | ucapI18n }}
|
||||||
|
</mat-option>
|
||||||
|
<mat-option value="20">
|
||||||
|
20{{ 'common:units.second' | ucapI18n }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="messenger-settings-area">
|
||||||
|
<div class="title-settings-subject">
|
||||||
|
{{
|
||||||
|
'organization:settings.notification.receiveForMobile'
|
||||||
|
| ucapI18n
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
<div class="settings-contents">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<mat-checkbox>
|
||||||
|
{{
|
||||||
|
'organization:settings.notification.receiveForMessageTypePopup'
|
||||||
|
| ucapI18n
|
||||||
|
}}
|
||||||
|
</mat-checkbox>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</mat-tab>
|
||||||
|
<mat-tab>
|
||||||
|
<ng-template mat-tab-label>
|
||||||
|
<p>{{ 'chat:settings.label' | ucapI18n }}</p>
|
||||||
|
</ng-template>
|
||||||
|
<div class="chat-settings-area">
|
||||||
|
<!-- 대화 -->
|
||||||
|
<div class="messenger-settings-area">
|
||||||
|
<div class="title-settings-subject">파일 전송</div>
|
||||||
|
<div class="settings-contents02">
|
||||||
|
<div class="subtitle-settings-info">
|
||||||
|
다운로드 폴더
|
||||||
|
</div>
|
||||||
|
<div class="settings-sub-content sub-set-content">
|
||||||
|
<mat-form-field
|
||||||
|
color="accent"
|
||||||
|
class="setting-input-obj input-set-obj ucap-mat-input-container"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
matInput
|
||||||
|
placeholder=""
|
||||||
|
value=""
|
||||||
|
[readonly]="'browser' === platform"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
mat-button
|
||||||
|
matSuffix
|
||||||
|
mat-icon-button
|
||||||
|
aria-label="file"
|
||||||
|
[disabled]="'browser' === platform"
|
||||||
|
>
|
||||||
|
<mat-icon>folder</mat-icon>
|
||||||
|
</button>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
mat-stroked-button
|
||||||
|
color="primary"
|
||||||
|
class="btn-folder-first"
|
||||||
|
[disabled]="'browser' === platform"
|
||||||
|
>
|
||||||
|
폴더 초기화
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</mat-tab>
|
||||||
|
<mat-tab>
|
||||||
|
<ng-template mat-tab-label>
|
||||||
|
<p>{{ 'call:settings.label' | ucapI18n }}</p>
|
||||||
|
</ng-template>
|
||||||
|
<div class="call-settings-area">
|
||||||
|
<!-- 통화 -->
|
||||||
|
<div class="messenger-settings-area">
|
||||||
|
<div class="title-settings-subject">
|
||||||
|
<span>Click to Call</span>
|
||||||
|
<em>
|
||||||
|
| PC Messenger에서 Click to Call 기능을 사용할 기기 설정</em
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="settings-contents">
|
||||||
|
<mat-radio-group
|
||||||
|
aria-label="Select an type of alarm"
|
||||||
|
class="settings-radio-group"
|
||||||
|
>
|
||||||
|
<mat-radio-button value="true">휴대폰</mat-radio-button>
|
||||||
|
<mat-radio-button value="false">사무실</mat-radio-button>
|
||||||
|
</mat-radio-group>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</mat-tab>
|
||||||
|
<mat-tab>
|
||||||
|
<ng-template mat-tab-label>
|
||||||
|
<p>{{ 'authentication:password.settings.label' | ucapI18n }}</p>
|
||||||
|
</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>
|
||||||
|
</div>
|
||||||
|
</mat-tab>
|
||||||
|
</mat-tab-group>
|
||||||
|
</div>
|
||||||
|
<div appLayoutsDefaultDialog="action" class="btn-box">
|
||||||
|
<button mat-stroked-button class="mat-basic" (click)="onCancel()">
|
||||||
|
{{ 'common:messages.cancel' | ucapI18n }}
|
||||||
|
</button>
|
||||||
|
<button mat-flat-button class="bg-primary-darkest" (click)="onConfirm()">
|
||||||
|
{{ 'common:messages.confirm' | ucapI18n }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</app-layouts-default-dialog>
|
||||||
|
</div>
|
|
@ -0,0 +1,224 @@
|
||||||
|
@import '~@ucap/lg-scss/mixins';
|
||||||
|
.dialog-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.dialog-body {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
.messenger-settings-area {
|
||||||
|
border-top: 10px solid #f1f2f6;
|
||||||
|
background-color: #fff;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px 16px 9px;
|
||||||
|
&:first-of-type {
|
||||||
|
border-top: 0;
|
||||||
|
padding: 20px 16px 9px;
|
||||||
|
}
|
||||||
|
.title-settings-subject {
|
||||||
|
color: #5c444b;
|
||||||
|
font-size: 1.071em;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.2;
|
||||||
|
padding: 6px 0 7px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
min-height: 30px;
|
||||||
|
span {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
em {
|
||||||
|
flex: 0 1 auto;
|
||||||
|
justify-self: start;
|
||||||
|
font-style: normal;
|
||||||
|
font-size: 0.929em;
|
||||||
|
color: #999;
|
||||||
|
font-weight: 400;
|
||||||
|
@include wordBreak();
|
||||||
|
@include ellipsis-column(1);
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.btn-subject-info {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
line-height: 30px;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.settings-contents {
|
||||||
|
ul {
|
||||||
|
li {
|
||||||
|
padding: 6px 0 7px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.settings-radio-group {
|
||||||
|
padding: 6px 0 7px;
|
||||||
|
height: 42px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
.mat-radio-button {
|
||||||
|
margin-left: 20%;
|
||||||
|
&:first-child {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.settings-contents02 {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 25px;
|
||||||
|
@include screen(xs) {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.subtitle-settings-info {
|
||||||
|
font-size: 0.929em;
|
||||||
|
color: #262626;
|
||||||
|
align-self: baseline;
|
||||||
|
@include screen(xs) {
|
||||||
|
flex: 1 0 auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.settings-sub-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-left: 25px;
|
||||||
|
width: 60%;
|
||||||
|
@include screen(xs) {
|
||||||
|
flex: 0 1 auto;
|
||||||
|
width: 100% !important;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
.setting-input-obj {
|
||||||
|
@include ucapMatFormField(0, 0, 0%, 100%, 100%, 60px, 11px);
|
||||||
|
overflow: hidden;
|
||||||
|
margin-top: 15px;
|
||||||
|
&:first-of-type {
|
||||||
|
margin-top: 0;
|
||||||
|
@include screen(xs) {
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.mat-hint {
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.sub-set-content {
|
||||||
|
width: auto;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
.input-set-obj {
|
||||||
|
@include ucapMatFormField(0, 0, 0%, 100%, 100%, 55px, 11px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.default-settings-area {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
.login-setting-box {
|
||||||
|
}
|
||||||
|
.language-setting-box,
|
||||||
|
.time-setting-box {
|
||||||
|
.settings-contents {
|
||||||
|
width: 50%;
|
||||||
|
height: 50px;
|
||||||
|
@include screen(mid) {
|
||||||
|
width: 70%;
|
||||||
|
}
|
||||||
|
@include screen(xs) {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.setting-select-obj {
|
||||||
|
@include ucapMatFormField(0, 0, 100%, 100%, 100%, 40px, 28px);
|
||||||
|
//@include ucapMatSelect(25px, 0 0);
|
||||||
|
|
||||||
|
.general-timezone-viewport {
|
||||||
|
height: 250px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.allim-settings-area {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
.allim-way-box,
|
||||||
|
.allim-time-box {
|
||||||
|
.settings-contents {
|
||||||
|
width: 50%;
|
||||||
|
height: 50px;
|
||||||
|
@include screen(mid) {
|
||||||
|
width: 70%;
|
||||||
|
}
|
||||||
|
@include screen(xs) {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.setting-select-obj {
|
||||||
|
@include ucapMatFormField(0, 0, 100%, 100%, 100%, 40px, 28px);
|
||||||
|
//@include ucapMatSelect(25px, 0 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.chat-settings-area {
|
||||||
|
}
|
||||||
|
.call-settings-area {
|
||||||
|
}
|
||||||
|
.secret-num-settings-area {
|
||||||
|
.pass-info-box {
|
||||||
|
dl {
|
||||||
|
border: 1px solid #dfe0e8;
|
||||||
|
background-color: #f7f8fa;
|
||||||
|
dt {
|
||||||
|
height: 30px;
|
||||||
|
background-color: #fff;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 0.857em;
|
||||||
|
font-weight: 600;
|
||||||
|
.bullet-ico-info {
|
||||||
|
flex: 0 0 36px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 16px;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
line-height: 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dd {
|
||||||
|
font-size: 0.857em;
|
||||||
|
color: #666;
|
||||||
|
line-height: 1.6;
|
||||||
|
margin: 2px 36px 3px;
|
||||||
|
&:first-of-type {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
&:last-of-type {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.btn-box {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-end;
|
||||||
|
button {
|
||||||
|
@include ucap-button-flat-stroked(120px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { By } from '@angular/platform-browser';
|
||||||
|
import { DebugElement } from '@angular/core';
|
||||||
|
|
||||||
|
import { SettingsDialogComponent } from './settings.dialog.component';
|
||||||
|
|
||||||
|
describe('app::account::SettingsDialogComponent', () => {
|
||||||
|
let component: SettingsDialogComponent;
|
||||||
|
let fixture: ComponentFixture<SettingsDialogComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [SettingsDialogComponent]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(SettingsDialogComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
189
src/app/dialogs/account/components/settings.dialog.component.ts
Normal file
189
src/app/dialogs/account/components/settings.dialog.component.ts
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
import moment from 'moment';
|
||||||
|
import 'moment-timezone';
|
||||||
|
|
||||||
|
import { Subject } from 'rxjs';
|
||||||
|
import { takeUntil } from 'rxjs/operators';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Component,
|
||||||
|
OnInit,
|
||||||
|
OnDestroy,
|
||||||
|
ChangeDetectionStrategy,
|
||||||
|
ChangeDetectorRef,
|
||||||
|
Inject,
|
||||||
|
ViewChild
|
||||||
|
} from '@angular/core';
|
||||||
|
|
||||||
|
import {
|
||||||
|
MatDialogRef,
|
||||||
|
MAT_DIALOG_DATA,
|
||||||
|
MatDialog
|
||||||
|
} from '@angular/material/dialog';
|
||||||
|
import { MatSelectChange, MatSelect } from '@angular/material/select';
|
||||||
|
|
||||||
|
import { NativeService, NativeType } from '@ucap/native';
|
||||||
|
|
||||||
|
import { UCAP_NATIVE_SERVICE } from '@ucap/ng-native';
|
||||||
|
|
||||||
|
import { environment } from '@environments';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Settings,
|
||||||
|
GeneralSetting,
|
||||||
|
NotificationSetting,
|
||||||
|
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;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SettingsDialogData {
|
||||||
|
settings: Settings;
|
||||||
|
}
|
||||||
|
export interface SettingsDialogResult {}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-sections-account-settings',
|
||||||
|
templateUrl: './settings.dialog.component.html',
|
||||||
|
styleUrls: ['./settings.dialog.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
|
})
|
||||||
|
export class SettingsDialogComponent implements OnInit, OnDestroy {
|
||||||
|
@ViewChild('vsTimezone', { static: false })
|
||||||
|
vsTimezone: VirtualScrollViewportComponent;
|
||||||
|
|
||||||
|
@ViewChild('selectForTimezone', { static: false })
|
||||||
|
selectForTimezone: MatSelect;
|
||||||
|
|
||||||
|
formControlForTimezone = new FormControl();
|
||||||
|
|
||||||
|
platform: 'browser' | 'electron' = 'electron';
|
||||||
|
|
||||||
|
generalSetting: GeneralSetting;
|
||||||
|
notificationSetting: NotificationSetting;
|
||||||
|
chatSetting: ChatSetting;
|
||||||
|
presenceSetting: PresenceSetting;
|
||||||
|
|
||||||
|
timezoneList: TimezoneData[];
|
||||||
|
timezonePlaceholder: string;
|
||||||
|
|
||||||
|
supportedLanguages = environment.productConfig.supportedLanguages;
|
||||||
|
supportedHrLanguages =
|
||||||
|
environment.productConfig.organization.supportedLanguages;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public dialogRef: MatDialogRef<SettingsDialogData, SettingsDialogResult>,
|
||||||
|
@Inject(MAT_DIALOG_DATA) public data: SettingsDialogData,
|
||||||
|
@Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService,
|
||||||
|
private i18nService: I18nService,
|
||||||
|
private changeDetectorRef: ChangeDetectorRef,
|
||||||
|
public matDialog: MatDialog
|
||||||
|
) {
|
||||||
|
this.nativeService.platform_nativeType().then((type) => {
|
||||||
|
switch (type) {
|
||||||
|
case NativeType.Browser:
|
||||||
|
this.platform = 'browser';
|
||||||
|
break;
|
||||||
|
case NativeType.Electron:
|
||||||
|
this.platform = 'electron';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.generalSetting = data.settings.general;
|
||||||
|
this.notificationSetting = data.settings.notification;
|
||||||
|
this.chatSetting = data.settings.chat;
|
||||||
|
this.presenceSetting = data.settings.presence;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ngOnDestroySubject: Subject<void> = new Subject();
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.generateTimezoneData();
|
||||||
|
|
||||||
|
this.i18nService.languageChanged$
|
||||||
|
.pipe(takeUntil(this.ngOnDestroySubject))
|
||||||
|
.subscribe((lang) => {
|
||||||
|
this.generateTimezoneData();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
if (!!this.ngOnDestroySubject) {
|
||||||
|
this.ngOnDestroySubject.next();
|
||||||
|
this.ngOnDestroySubject.complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onSelectionChangeLanguage(event: MatSelectChange) {}
|
||||||
|
|
||||||
|
onSelectionChangeHrLanguage(event: MatSelectChange) {}
|
||||||
|
|
||||||
|
onOpenedChangeTimezone(opened: boolean) {
|
||||||
|
if (opened) {
|
||||||
|
this.setTimezoneData();
|
||||||
|
this.vsTimezone.checkViewportSize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onSelectionChangeTimezone(event: MatOptionSelectionChange) {
|
||||||
|
if (!event.isUserInput) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onClosed(event: MouseEvent): void {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
onCancel() {}
|
||||||
|
|
||||||
|
onConfirm() {}
|
||||||
|
|
||||||
|
private generateTimezoneData() {
|
||||||
|
const timezoneData = this.i18nService.t('locale:timezone', {
|
||||||
|
returnObjects: true
|
||||||
|
});
|
||||||
|
|
||||||
|
let timezoneList: TimezoneData[] = [];
|
||||||
|
for (const name of moment.tz.names()) {
|
||||||
|
const displayName = `(UTC${moment.tz(name).format('Z')}) ${
|
||||||
|
timezoneData[name]
|
||||||
|
}`;
|
||||||
|
timezoneList.push({
|
||||||
|
displayName,
|
||||||
|
name
|
||||||
|
});
|
||||||
|
if (name === this.generalSetting.timezone) {
|
||||||
|
this.timezonePlaceholder = displayName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
timezoneList = timezoneList.sort((a: TimezoneData, b: TimezoneData) => {
|
||||||
|
return a.displayName.localeCompare(b.displayName);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.timezoneList = timezoneList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private setTimezoneData() {
|
||||||
|
const timezoneIndex = this.timezoneList.findIndex(
|
||||||
|
(t) => t.name === this.generalSetting.timezone
|
||||||
|
);
|
||||||
|
|
||||||
|
if (-1 !== timezoneIndex) {
|
||||||
|
if (!!this.vsTimezone && !!this.selectForTimezone) {
|
||||||
|
this.vsTimezone.scrollToIndex(timezoneIndex);
|
||||||
|
this.selectForTimezone.value = this.timezoneList[timezoneIndex].name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,17 @@
|
||||||
<div class="layout-container" fxLayout="column">
|
<div class="layout-container" fxLayout="column">
|
||||||
<div class="layout-header" fxFlex="60px" fxLayout="row">
|
<div class="layout-header" fxFlex="50px" fxLayout="row">
|
||||||
<div fxFlex="1 1 auto">
|
<div fxFlex="1 1 auto">
|
||||||
<ng-content
|
<ng-content
|
||||||
class="layout-header-content"
|
class="layout-header-content"
|
||||||
select="[appLayoutsDefaultDialog='header']"
|
select="[appLayoutsDefaultDialog='header']"
|
||||||
></ng-content>
|
></ng-content>
|
||||||
</div>
|
</div>
|
||||||
|
<div fxFlex="1 0 auto">
|
||||||
|
<ng-content
|
||||||
|
class="layout-sub-header-content"
|
||||||
|
select="[appLayoutsDefaultDialog='sub-header']"
|
||||||
|
></ng-content>
|
||||||
|
</div>
|
||||||
<div fxFlex="30px" *ngIf="!disableClose">
|
<div fxFlex="30px" *ngIf="!disableClose">
|
||||||
<button
|
<button
|
||||||
class="icon-button btn-dialog-close"
|
class="icon-button btn-dialog-close"
|
||||||
|
@ -15,13 +21,11 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layout-body" fxFlex="1 1 auto">
|
<div class="layout-body" fxFlex="1 1 auto" perfectScrollbar>
|
||||||
<perfect-scrollbar style="width: 100%; height: 100%;">
|
<ng-content
|
||||||
<ng-content
|
class="layout-body-content"
|
||||||
class="layout-body-content"
|
select="[appLayoutsDefaultDialog='body']"
|
||||||
select="[appLayoutsDefaultDialog='body']"
|
></ng-content>
|
||||||
></ng-content>
|
|
||||||
</perfect-scrollbar>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="layout-action" fxFlex="60px">
|
<div class="layout-action" fxFlex="60px">
|
||||||
<ng-content
|
<ng-content
|
||||||
|
|
|
@ -3,6 +3,13 @@
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
.layout-header {
|
.layout-header {
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
color: #333;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 1.143em;
|
||||||
|
border-bottom: 1px solid #666;
|
||||||
|
margin: 0 16px;
|
||||||
.layout-header-content {
|
.layout-header-content {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -17,6 +24,9 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.layout-action {
|
.layout-action {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
.layout-action-content {
|
.layout-action-content {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
|
@ -4,14 +4,8 @@ import {
|
||||||
Component,
|
Component,
|
||||||
OnInit,
|
OnInit,
|
||||||
OnDestroy,
|
OnDestroy,
|
||||||
AfterViewInit,
|
|
||||||
ChangeDetectionStrategy,
|
ChangeDetectionStrategy,
|
||||||
ChangeDetectorRef,
|
ChangeDetectorRef,
|
||||||
Inject,
|
|
||||||
ViewChild,
|
|
||||||
ComponentFactoryResolver,
|
|
||||||
ViewContainerRef,
|
|
||||||
ComponentRef,
|
|
||||||
Input,
|
Input,
|
||||||
EventEmitter,
|
EventEmitter,
|
||||||
Output
|
Output
|
||||||
|
@ -40,6 +34,7 @@ export class DefaultDialogLayoutComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
if (!!this.ngOnDestroySubject) {
|
if (!!this.ngOnDestroySubject) {
|
||||||
|
this.ngOnDestroySubject.next();
|
||||||
this.ngOnDestroySubject.complete();
|
this.ngOnDestroySubject.complete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
<div class="layout-container" fxLayout="column">
|
||||||
|
<div class="layout-header" fxFlex="60px" fxLayout="row">
|
||||||
|
<div fxFlex="1 1 auto">
|
||||||
|
<ng-content
|
||||||
|
class="layout-header-content"
|
||||||
|
select="[appLayoutsDefaultDrawer='header']"
|
||||||
|
></ng-content>
|
||||||
|
</div>
|
||||||
|
<div fxFlex="30px" *ngIf="!disableClose">
|
||||||
|
<button
|
||||||
|
class="icon-button btn-dialog-close"
|
||||||
|
(click)="onClickClose($event)"
|
||||||
|
>
|
||||||
|
<i class="mdi mdi-window-close"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layout-body" fxFlex="1 1 auto">
|
||||||
|
<perfect-scrollbar style="width: 100%; height: 100%;">
|
||||||
|
<ng-content
|
||||||
|
class="layout-body-content"
|
||||||
|
select="[appLayoutsDefaultDrawer='body']"
|
||||||
|
></ng-content>
|
||||||
|
</perfect-scrollbar>
|
||||||
|
</div>
|
||||||
|
<div class="layout-action" fxFlex="60px">
|
||||||
|
<ng-content
|
||||||
|
class="layout-action-content"
|
||||||
|
select="[appLayoutsDefaultDrawer='action']"
|
||||||
|
></ng-content>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,35 @@
|
||||||
|
.layout-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.layout-header {
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
color: #333;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 1.143em;
|
||||||
|
border-bottom: 1px solid #333;
|
||||||
|
margin: 0 16px;
|
||||||
|
.layout-header-content {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.layout-body {
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
.layout-body-content {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.layout-action {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
.layout-action-content {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { By } from '@angular/platform-browser';
|
||||||
|
import { DebugElement } from '@angular/core';
|
||||||
|
|
||||||
|
import { DefaultDrawerLayoutComponent } from './default-drawer.layout.component';
|
||||||
|
|
||||||
|
describe('app::layouts::DefaultDrawerLayoutComponent', () => {
|
||||||
|
let component: DefaultDrawerLayoutComponent;
|
||||||
|
let fixture: ComponentFixture<DefaultDrawerLayoutComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [DefaultDrawerLayoutComponent]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(DefaultDrawerLayoutComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,45 @@
|
||||||
|
import { Subject } from 'rxjs';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Component,
|
||||||
|
OnInit,
|
||||||
|
OnDestroy,
|
||||||
|
ChangeDetectionStrategy,
|
||||||
|
ChangeDetectorRef,
|
||||||
|
Input,
|
||||||
|
EventEmitter,
|
||||||
|
Output
|
||||||
|
} from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-layouts-default-drawer',
|
||||||
|
templateUrl: './default-drawer.layout.component.html',
|
||||||
|
styleUrls: ['./default-drawer.layout.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
|
})
|
||||||
|
export class DefaultDrawerLayoutComponent implements OnInit, OnDestroy {
|
||||||
|
@Input()
|
||||||
|
disableClose = false;
|
||||||
|
|
||||||
|
@Output()
|
||||||
|
closed = new EventEmitter<MouseEvent>();
|
||||||
|
|
||||||
|
constructor(private changeDetectorRef: ChangeDetectorRef) {}
|
||||||
|
|
||||||
|
private ngOnDestroySubject: Subject<boolean>;
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.ngOnDestroySubject = new Subject<boolean>();
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
if (!!this.ngOnDestroySubject) {
|
||||||
|
this.ngOnDestroySubject.next();
|
||||||
|
this.ngOnDestroySubject.complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickClose(event: MouseEvent): void {
|
||||||
|
this.closed.emit(event);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,12 +3,13 @@
|
||||||
<div class="gnb">
|
<div class="gnb">
|
||||||
<mat-toolbar class="mat-gnb-toolbar"
|
<mat-toolbar class="mat-gnb-toolbar"
|
||||||
><img
|
><img
|
||||||
src="../../../assets/images/logo_140.png"
|
src="assets/images/logo_140.png"
|
||||||
alt=""
|
alt=""
|
||||||
class="img-logo"
|
class="img-logo"
|
||||||
width="32"
|
width="32"
|
||||||
/></mat-toolbar>
|
/></mat-toolbar>
|
||||||
<mat-tab-group
|
<mat-tab-group
|
||||||
|
#navTabGroup
|
||||||
mat-stretch-tabs
|
mat-stretch-tabs
|
||||||
animationDuration="0ms"
|
animationDuration="0ms"
|
||||||
backgroundColor="transparent"
|
backgroundColor="transparent"
|
||||||
|
@ -17,7 +18,12 @@
|
||||||
>
|
>
|
||||||
<mat-tab aria-label="Group">
|
<mat-tab aria-label="Group">
|
||||||
<ng-template mat-tab-label>
|
<ng-template mat-tab-label>
|
||||||
<div class="icon-item" matTooltip="그룹" matTooltipPosition="after">
|
<div
|
||||||
|
class="icon-item"
|
||||||
|
[matTooltip]="'common:tooltip.group' | ucapI18n"
|
||||||
|
matTooltipPosition="after"
|
||||||
|
(click)="onClickToggleLeftSidenav()"
|
||||||
|
>
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="16.871"
|
width="16.871"
|
||||||
|
@ -63,10 +69,13 @@
|
||||||
<ng-template mat-tab-label>
|
<ng-template mat-tab-label>
|
||||||
<div
|
<div
|
||||||
class="icon-item"
|
class="icon-item"
|
||||||
matBadgeHidden="false"
|
[matTooltip]="'common:tooltip.chat' | ucapI18n"
|
||||||
matBadge="275"
|
matTooltipPosition="after"
|
||||||
|
[matBadgeHidden]="unreadCountChat <= 0"
|
||||||
|
[matBadge]="unreadCountChat"
|
||||||
matBadgeColor="accent"
|
matBadgeColor="accent"
|
||||||
matBadgePosition="above after"
|
matBadgePosition="above after"
|
||||||
|
(click)="onClickToggleLeftSidenav()"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
@ -95,7 +104,12 @@
|
||||||
</mat-tab>
|
</mat-tab>
|
||||||
<mat-tab aria-label="Organization">
|
<mat-tab aria-label="Organization">
|
||||||
<ng-template mat-tab-label>
|
<ng-template mat-tab-label>
|
||||||
<div class="icon-item">
|
<div
|
||||||
|
class="icon-item"
|
||||||
|
[matTooltip]="'common:tooltip.organization' | ucapI18n"
|
||||||
|
matTooltipPosition="after"
|
||||||
|
(click)="onClickToggleLeftSidenav()"
|
||||||
|
>
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="21"
|
width="21"
|
||||||
|
@ -146,7 +160,12 @@
|
||||||
|
|
||||||
<mat-tab aria-label="Message">
|
<mat-tab aria-label="Message">
|
||||||
<ng-template mat-tab-label>
|
<ng-template mat-tab-label>
|
||||||
<div class="icon-item">
|
<div
|
||||||
|
class="icon-item"
|
||||||
|
[matTooltip]="'common:tooltip.message' | ucapI18n"
|
||||||
|
matTooltipPosition="after"
|
||||||
|
(click)="onClickToggleLeftSidenav()"
|
||||||
|
>
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="21.096"
|
width="21.096"
|
||||||
|
@ -180,7 +199,12 @@
|
||||||
|
|
||||||
<mat-tab aria-label="Call">
|
<mat-tab aria-label="Call">
|
||||||
<ng-template mat-tab-label>
|
<ng-template mat-tab-label>
|
||||||
<div class="icon-item">
|
<div
|
||||||
|
class="icon-item"
|
||||||
|
[matTooltip]="'common:tooltip.call' | ucapI18n"
|
||||||
|
matTooltipPosition="after"
|
||||||
|
(click)="onClickToggleLeftSidenav()"
|
||||||
|
>
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="18"
|
width="18"
|
||||||
|
@ -208,27 +232,159 @@
|
||||||
</mat-tab-group>
|
</mat-tab-group>
|
||||||
|
|
||||||
<div class="btn-homepage-area">
|
<div class="btn-homepage-area">
|
||||||
<button mat-button aria-label="">
|
<button mat-button aria-label="Homepage" matTooltip="Homepage">
|
||||||
<em>Homepage</em>
|
<!--<em>Homepage</em>-->
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ucap-float-action-button
|
|
||||||
*ngIf="fabButtonShow"
|
|
||||||
[buttons]="fabButtons"
|
|
||||||
(buttonClick)="onClickFab($event)"
|
|
||||||
>
|
|
||||||
</ucap-float-action-button>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="content-page" fxFlex="1 1 auto" fxLayout="column">
|
<div class="content-page" fxFlex="1 1 auto" fxLayout="column">
|
||||||
<div class="content-body" fxFlex="1 1 auto">
|
<div class="content-body" fxFlex="1 1 auto">
|
||||||
<mat-sidenav-container autosize="true">
|
<mat-sidenav-container hasBackdrop="false" autosize="true">
|
||||||
<mat-sidenav
|
<mat-sidenav
|
||||||
#leftSidenav
|
#leftSidenav
|
||||||
class="left-sidenav"
|
class="left-sidenav"
|
||||||
mode="side"
|
mode="side"
|
||||||
opened="true"
|
opened="true"
|
||||||
|
[disableClose]="true"
|
||||||
>
|
>
|
||||||
|
<ucap-float-action-button
|
||||||
|
*ngIf="fabButtonShow"
|
||||||
|
[buttons]="fabButtons"
|
||||||
|
[useCustomDefaultIcon]="fabUseCustomDefaultIcon"
|
||||||
|
(buttonClick)="onClickFab($event)"
|
||||||
|
>
|
||||||
|
<div *ngIf="tabIndex === 'group'" ucapFloatActionButton="mainIcon">
|
||||||
|
<mat-icon class="ico-font-float">
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="44"
|
||||||
|
height="44"
|
||||||
|
viewBox="0 0 44 44"
|
||||||
|
>
|
||||||
|
<g transform="translate(4 7)">
|
||||||
|
<path
|
||||||
|
fill="none"
|
||||||
|
d="M0 0H44V44H0z"
|
||||||
|
transform="translate(-4 -7)"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M0 0L12 0"
|
||||||
|
class="prefix_cls-2"
|
||||||
|
transform="translate(24.357 7.26)"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M0 0L12 0"
|
||||||
|
class="prefix_cls-2"
|
||||||
|
transform="rotate(90 14.549 16.049)"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
fill="rgba(0,0,0,0)"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="bevel"
|
||||||
|
stroke-miterlimit="10"
|
||||||
|
stroke-width="3px"
|
||||||
|
d="M26.25 24.125a11.125 11.125 0 1 0-22.25 0"
|
||||||
|
class="prefix_cls-3"
|
||||||
|
transform="translate(-3.5 2.657)"
|
||||||
|
/>
|
||||||
|
<g fill="none" stroke="none">
|
||||||
|
<path
|
||||||
|
d="M7.08 0a7.08 7.08 0 0 1 7.08 7.08 7.318 7.318 0 0 1-2.753 5.6 6.7 6.7 0 0 1-4.327 1.479A7.08 7.08 0 0 1 7.08 0z"
|
||||||
|
transform="translate(5 1)"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M7.08 3C4.83 3 3 4.83 3 7.08c0 2.249 1.83 4.08 4.08 4.08 1.164 0 2.06-.466 2.289-.678l.026-.024.026-.024c1.558-1.374 1.738-2.573 1.738-3.354C11.16 4.83 9.33 3 7.08 3m0-3c3.91 0 7.08 3.17 7.08 7.08 0 2.095-.91 3.978-2.753 5.604-.857.793-2.512 1.475-4.326 1.475C3.17 14.16 0 10.99 0 7.08S3.17 0 7.08 0z"
|
||||||
|
class="prefix_cls-4"
|
||||||
|
transform="translate(5 1)"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</mat-icon>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="tabIndex === 'chat'" ucapFloatActionButton="mainIcon">
|
||||||
|
<mat-icon class="ico-font-float">
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="44"
|
||||||
|
height="44"
|
||||||
|
viewBox="0 0 44 44"
|
||||||
|
>
|
||||||
|
<g transform="translate(-10 -10)">
|
||||||
|
<path
|
||||||
|
fill="none"
|
||||||
|
d="M0 0H44V44H0z"
|
||||||
|
transform="translate(10 10)"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M0 0L12 0"
|
||||||
|
class="prefix_cls-2"
|
||||||
|
transform="translate(40.625 22.552)"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M0 0L12 0"
|
||||||
|
class="prefix_cls-2"
|
||||||
|
transform="rotate(90 15.036 31.829)"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
fill="rgba(102,102,102,0)"
|
||||||
|
class="prefix_cls-3"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="3px"
|
||||||
|
d="M50.353 28.582a13.829 13.829 0 0 0-17.546 0 10.012 10.012 0 0 0 0 15.588 13.406 13.406 0 0 0 8.773 3.139c.337 0 .676-.012 1.013-.036l2.129 3.737a.837.837 0 0 0 .7.433h.02a.832.832 0 0 0 .7-.4l4.511-7.143a9.995 9.995 0 0 0-.3-15.319z"
|
||||||
|
data-name="icon_float_chat"
|
||||||
|
transform="translate(-16.272 -6.943)"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</mat-icon>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
*ngIf="tabIndex === 'message'"
|
||||||
|
ucapFloatActionButton="mainIcon"
|
||||||
|
>
|
||||||
|
<mat-icon class="ico-font-float">
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="44"
|
||||||
|
height="44"
|
||||||
|
viewBox="0 0 44 44"
|
||||||
|
>
|
||||||
|
<g transform="translate(-10 -9.5)">
|
||||||
|
<path
|
||||||
|
fill="none"
|
||||||
|
d="M0 0H44V44H0z"
|
||||||
|
transform="translate(10 9.5)"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M0 0L12 0"
|
||||||
|
class="prefix_cls-2"
|
||||||
|
transform="translate(40.5 38.26)"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M0 0L12 0"
|
||||||
|
class="prefix_cls-2"
|
||||||
|
transform="rotate(90 7.12 39.62)"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
fill="none"
|
||||||
|
class="prefix_cls-3"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="3px"
|
||||||
|
d="M22.425 3.3a3.851 3.851 0 0 1 5.447 5.447L9.489 27.129 2 29.172l2.043-7.489z"
|
||||||
|
data-name="icon_float_message"
|
||||||
|
transform="translate(11.5 14.328)"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</mat-icon>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="tabIndex === 'call'" ucapFloatActionButton="mainIcon">
|
||||||
|
<mat-icon class="ico-font-dialpad">dialpad</mat-icon>
|
||||||
|
</div>
|
||||||
|
</ucap-float-action-button>
|
||||||
<div class="left-sidenav-container" fxLayout="column">
|
<div class="left-sidenav-container" fxLayout="column">
|
||||||
<div class="top-bar" fxFlex="0 0 40px">
|
<div class="top-bar" fxFlex="0 0 40px">
|
||||||
M-Messenger
|
M-Messenger
|
||||||
|
@ -242,7 +398,41 @@
|
||||||
<mat-sidenav-content>
|
<mat-sidenav-content>
|
||||||
<div class="content-sidenav-container" fxLayout="column">
|
<div class="content-sidenav-container" fxLayout="column">
|
||||||
<div class="content-sidenav-top-bar" fxFlex="0 0 40px">
|
<div class="content-sidenav-top-bar" fxFlex="0 0 40px">
|
||||||
<app-layouts-top-bar></app-layouts-top-bar>
|
<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>
|
||||||
|
<div class="toolbar-info-area toolbar-ctrl">
|
||||||
|
<!--Search-->
|
||||||
|
<div class="topbar-search">
|
||||||
|
<button
|
||||||
|
mat-icon-button
|
||||||
|
aria-label="search icon"
|
||||||
|
(click)="onClickSearch($event)"
|
||||||
|
>
|
||||||
|
<mat-icon class="ico-search-icon">search</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--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"
|
||||||
|
(openProfile)="onOpenProfile($event)"
|
||||||
|
></app-organization-profile-image-01>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</app-layouts-top-bar>
|
||||||
</div>
|
</div>
|
||||||
<div class="content-sidenav-body" fxFlex="1 1 auto">
|
<div class="content-sidenav-body" fxFlex="1 1 auto">
|
||||||
<router-outlet name="content"></router-outlet>
|
<router-outlet name="content"></router-outlet>
|
||||||
|
@ -269,3 +459,16 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<mat-menu #profileMenu="matMenu" class="profile-menu-panel">
|
||||||
|
<ng-template matMenuContent>
|
||||||
|
<app-organization-profile-menu-01
|
||||||
|
(selectedProfileManage)="onSelectedProfileManage()"
|
||||||
|
(selectedNotice)="onSelectedNotice()"
|
||||||
|
(selectedSettings)="onSelectedSettings()"
|
||||||
|
(selectedLogout)="onSelectedLogout()"
|
||||||
|
(selectedExit)="onSelectedExit()"
|
||||||
|
(done)="onDoneForProfileMenu()"
|
||||||
|
></app-organization-profile-menu-01>
|
||||||
|
</ng-template>
|
||||||
|
</mat-menu>
|
||||||
|
|
|
@ -12,18 +12,20 @@
|
||||||
.navitab-page {
|
.navitab-page {
|
||||||
//GNB /////////////////////////////////////
|
//GNB /////////////////////////////////////
|
||||||
.gnb {
|
.gnb {
|
||||||
background-color: $gray-ref0;
|
//background-color: $gray-ref0;
|
||||||
|
background-color: #f1f2f6;
|
||||||
width: 60px;
|
width: 60px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-right: 1px solid rgba(204, 204, 204, 0.8);
|
border-right: 1px solid rgba(0, 0, 0, 0.2);
|
||||||
.mat-gnb-toolbar {
|
.mat-gnb-toolbar {
|
||||||
flex-basis: 64px;
|
flex-basis: 40px;
|
||||||
|
padding: 2px 12px 10px;
|
||||||
.img-logo {
|
.img-logo {
|
||||||
margin: 9px 0 5px;
|
margin: 6px 0 0 1px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.left-container {
|
.left-container {
|
||||||
|
@ -33,13 +35,14 @@
|
||||||
}
|
}
|
||||||
.global-menu {
|
.global-menu {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: $gray-ref0;
|
//background-color: $gray-ref0;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
.btn-homepage-area {
|
.btn-homepage-area {
|
||||||
flex-flow: column-reverse;
|
flex-flow: column-reverse;
|
||||||
position: relative;
|
position: relative;
|
||||||
button {
|
button {
|
||||||
|
/*
|
||||||
padding: 30px 0 12px;
|
padding: 30px 0 12px;
|
||||||
&::before {
|
&::before {
|
||||||
content: '';
|
content: '';
|
||||||
|
@ -51,6 +54,21 @@
|
||||||
top: 9px;
|
top: 9px;
|
||||||
left: calc(50% - 10px);
|
left: calc(50% - 10px);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
padding: 30px 0 12px;
|
||||||
|
border-radius: 21px;
|
||||||
|
min-width: 42px;
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
background-image: url(../../../assets/images/ico/btn_gnb_hompage.svg);
|
||||||
|
background-size: 30px;
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: 5px;
|
||||||
|
left: calc(50% - 15px);
|
||||||
|
}
|
||||||
em {
|
em {
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-size: 8px;
|
font-size: 8px;
|
||||||
|
@ -61,139 +79,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
::ng-deep .global-menu {
|
|
||||||
//display: flex;
|
|
||||||
//flex-direction: row;
|
|
||||||
.mat-tab-header {
|
|
||||||
border-bottom: none !important;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.mat-tab-label-container {
|
|
||||||
.mat-tab-list {
|
|
||||||
.mat-tab-labels {
|
|
||||||
display: flex;
|
|
||||||
flex-flow: column;
|
|
||||||
justify-content: space-around;
|
|
||||||
height: 272px;
|
|
||||||
border-bottom: none;
|
|
||||||
|
|
||||||
.mat-tab-label {
|
|
||||||
width: 100%;
|
|
||||||
height: 32px;
|
|
||||||
padding: 0;
|
|
||||||
min-width: 0 !important;
|
|
||||||
.mat-tab-label-content {
|
|
||||||
.icon-item {
|
|
||||||
display: inline-flex;
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
border-radius: 50%;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
//transform: scale(0.9);
|
|
||||||
transition: transform 0.3s cubic-bezier(0.4, 0, 0, 1);
|
|
||||||
|
|
||||||
svg {
|
|
||||||
//width: 24px;
|
|
||||||
//height: 24px;
|
|
||||||
stroke: $gray-re9;
|
|
||||||
stroke-width: 2;
|
|
||||||
stroke-linecap: square;
|
|
||||||
stroke-linejoin: miter;
|
|
||||||
fill: none;
|
|
||||||
g {
|
|
||||||
&#icon_gnb_organiztion_g32 {
|
|
||||||
.prefix__cls-1,
|
|
||||||
.prefix__cls-4 {
|
|
||||||
fill: none;
|
|
||||||
}
|
|
||||||
.prefix__cls-1 {
|
|
||||||
stroke: #999;
|
|
||||||
stroke-width: 2px;
|
|
||||||
}
|
|
||||||
.prefix__cls-3 {
|
|
||||||
stroke: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&#icon_gnb_message_g32 {
|
|
||||||
.prefix__cls-1 {
|
|
||||||
fill: none;
|
|
||||||
stroke: #999;
|
|
||||||
stroke-width: 2px;
|
|
||||||
stroke-linejoin: round;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.mat-badge-content {
|
|
||||||
right: -9px !important;
|
|
||||||
border: 1px solid #ffbf2a;
|
|
||||||
//width: 24px;
|
|
||||||
//height: 24px;
|
|
||||||
box-sizing: content-box;
|
|
||||||
top: -10px !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.mat-tab-label-active {
|
|
||||||
opacity: 0;
|
|
||||||
svg {
|
|
||||||
stroke: #fff !important;
|
|
||||||
g {
|
|
||||||
&#prefix_23,
|
|
||||||
&#icon_gnb_chat_g32,
|
|
||||||
&#icon_gnb_call_g32 {
|
|
||||||
path {
|
|
||||||
&:nth-child(2) {
|
|
||||||
fill: #fff !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&#icon_gnb_organiztion_g32 {
|
|
||||||
.prefix__cls-1 {
|
|
||||||
stroke: #fff !important;
|
|
||||||
}
|
|
||||||
path {
|
|
||||||
&:nth-last-of-type(2) {
|
|
||||||
stroke: #fff !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&#icon_gnb_message_g32 {
|
|
||||||
.prefix__cls-1 {
|
|
||||||
stroke: #fff !important;
|
|
||||||
}
|
|
||||||
path {
|
|
||||||
&:nth-child(3) {
|
|
||||||
stroke: #fff !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&[aria-selected='true'] {
|
|
||||||
opacity: 1;
|
|
||||||
.mat-tab-label-content {
|
|
||||||
.icon-item {
|
|
||||||
transform: scale(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.mat-ink-bar {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.mat-tab-body-wrapper {
|
|
||||||
.mat-tab-body {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/////////////////////////////////////GNB //
|
/////////////////////////////////////GNB //
|
||||||
}
|
}
|
||||||
|
@ -213,6 +98,7 @@
|
||||||
.left-sidenav {
|
.left-sidenav {
|
||||||
width: 370px;
|
width: 370px;
|
||||||
max-width: 90%;
|
max-width: 90%;
|
||||||
|
border-right: 1px solid rgba(0, 0, 0, 0.2);
|
||||||
|
|
||||||
.left-sidenav-container {
|
.left-sidenav-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -222,8 +108,10 @@
|
||||||
size: 13px;
|
size: 13px;
|
||||||
color: $gray-re70;
|
color: $gray-re70;
|
||||||
}
|
}
|
||||||
line-height: 15px;
|
height: 40px;
|
||||||
padding: 25px 0 0 17px;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 16px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -232,6 +120,96 @@
|
||||||
.content-sidenav-container {
|
.content-sidenav-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
overflow: hidden; //20200611
|
||||||
|
.content-sidenav-top-bar {
|
||||||
|
.content-sidenav-top-bar-content {
|
||||||
|
height: 40px;
|
||||||
|
width: auto;
|
||||||
|
background-color: transparent;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
flex-grow: 1;
|
||||||
|
font-size: 12px;
|
||||||
|
justify-content: space-between;
|
||||||
|
.toolbar-info-area {
|
||||||
|
display: flex;
|
||||||
|
flex-grow: 1;
|
||||||
|
align-items: center;
|
||||||
|
&.date-info {
|
||||||
|
@include font-family($font-light);
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 12px;
|
||||||
|
color: $gray-re70;
|
||||||
|
padding-left: 30px;
|
||||||
|
@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;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: $lipstick;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.toolbar-ctrl {
|
||||||
|
flex-flow: row-reverse;
|
||||||
|
.topbar-search {
|
||||||
|
order: 2;
|
||||||
|
margin-right: 8px;
|
||||||
|
.ico-search-icon {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 18px;
|
||||||
|
color: #707070;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.my-profile {
|
||||||
|
height: 30px;
|
||||||
|
width: 30px;
|
||||||
|
margin-right: 20px;
|
||||||
|
order: 1;
|
||||||
|
//profile /////////////
|
||||||
|
.user-profile-thumb {
|
||||||
|
@include profile-avatar-default(
|
||||||
|
0,
|
||||||
|
14,
|
||||||
|
$green,
|
||||||
|
18px
|
||||||
|
); //오른 아래 공간, 모바일 온라인 아이콘 크기, 모바일 아이콘 색, 모바일 아이콘 bg크기
|
||||||
|
|
||||||
|
.presence {
|
||||||
|
//PC 상태
|
||||||
|
@include presence-state(10px); //원크기
|
||||||
|
position: relative;
|
||||||
|
align-self: flex-end;
|
||||||
|
margin-left: -10px;
|
||||||
|
order: 2;
|
||||||
|
}
|
||||||
|
.profileImage {
|
||||||
|
@include avatar-img(30px, 0); //아바타 크기, 왼쪽공간
|
||||||
|
order: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
///// profile//
|
||||||
|
}
|
||||||
|
.app-layout-native-title-bar-actions {
|
||||||
|
order: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.content-sidenav-body {
|
.content-sidenav-body {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
@ -250,7 +228,7 @@
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 38px;
|
height: 38px;
|
||||||
border-top: 1px solid $line-color-gray01;
|
border-top: 1px solid rgba(0, 0, 0, 0.2);
|
||||||
background-color: $white;
|
background-color: $white;
|
||||||
.foot-info {
|
.foot-info {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -264,6 +242,13 @@
|
||||||
.var-txt {
|
.var-txt {
|
||||||
padding-left: 8px;
|
padding-left: 8px;
|
||||||
color: $gray-re70;
|
color: $gray-re70;
|
||||||
|
text-align: center;
|
||||||
|
@include screen(custom, max, 414) {
|
||||||
|
padding-left: 22px;
|
||||||
|
flex-basis: 38%;
|
||||||
|
flex-grow: 0;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
&::before {
|
&::before {
|
||||||
content: '';
|
content: '';
|
||||||
width: 1px;
|
width: 1px;
|
||||||
|
@ -271,10 +256,19 @@
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
background-color: #d4d4d4;
|
background-color: #d4d4d4;
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
|
@include screen(custom, max, 414) {
|
||||||
|
margin-left: -10px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
&:first-of-type {
|
&:first-of-type {
|
||||||
|
@include screen(custom, max, 414) {
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
&::before {
|
&::before {
|
||||||
width: 0;
|
width: 0;
|
||||||
|
@include screen(custom, max, 414) {
|
||||||
|
margin-left: -4px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.new-var {
|
&.new-var {
|
||||||
|
@ -287,11 +281,13 @@
|
||||||
padding-right: 20px;
|
padding-right: 20px;
|
||||||
p {
|
p {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
text-align: right;
|
||||||
span {
|
span {
|
||||||
color: $lipstick;
|
color: $lipstick;
|
||||||
}
|
}
|
||||||
em {
|
em {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -301,3 +297,41 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Float action button
|
||||||
|
.ico-font-float {
|
||||||
|
svg {
|
||||||
|
.prefix_cls-2 {
|
||||||
|
fill: transparent;
|
||||||
|
stroke-width: 2px;
|
||||||
|
stroke: rgba(255, 255, 255, 1);
|
||||||
|
}
|
||||||
|
.prefix_cls-3 {
|
||||||
|
stroke: rgba(255, 255, 255, 1);
|
||||||
|
}
|
||||||
|
.prefix_cls-4 {
|
||||||
|
fill: rgba(255, 255, 255, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
svg {
|
||||||
|
.prefix_cls-2 {
|
||||||
|
stroke: rgba(255, 255, 255, 0.7);
|
||||||
|
}
|
||||||
|
.prefix_cls-3 {
|
||||||
|
stroke: rgba(255, 255, 255, 0.7);
|
||||||
|
}
|
||||||
|
.prefix_cls-4 {
|
||||||
|
fill: rgba(255, 255, 255, 0.7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ico-font-dialpad {
|
||||||
|
font-size: 28px !important;
|
||||||
|
line-height: 44px;
|
||||||
|
&:hover {
|
||||||
|
color: rgba(255, 255, 255, 0.7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,17 +1,40 @@
|
||||||
import { Subscription } from 'rxjs';
|
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 } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
import {
|
||||||
|
Router,
|
||||||
|
RouterEvent,
|
||||||
|
NavigationEnd,
|
||||||
|
PRIMARY_OUTLET,
|
||||||
|
ActivatedRoute,
|
||||||
|
Params
|
||||||
|
} from '@angular/router';
|
||||||
|
|
||||||
import { Store, select } from '@ngrx/store';
|
import { Store, select } from '@ngrx/store';
|
||||||
|
|
||||||
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
|
import { MatMenuTrigger } from '@angular/material/menu';
|
||||||
import { MatTabChangeEvent, MatTabGroup } from '@angular/material/tabs';
|
import { MatTabChangeEvent, MatTabGroup } from '@angular/material/tabs';
|
||||||
import { MatSidenav } from '@angular/material/sidenav';
|
import { MatSidenav } from '@angular/material/sidenav';
|
||||||
|
|
||||||
|
import { VersionInfo2Response } from '@ucap/api-public';
|
||||||
|
import { UserInfoSS } from '@ucap/protocol-query';
|
||||||
|
|
||||||
import { LogService } from '@ucap/ng-logger';
|
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 { AppSelector } from '@app/store/state';
|
||||||
import { AppChatService } from '@app/services/app-chat.service';
|
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 { QueryParams as OrganizationParams } from '@app/pages/organization/types/params.type';
|
||||||
|
import { User } from '@ucap/protocol-info';
|
||||||
|
|
||||||
const NAVS = ['group', 'chat', 'organization', 'message'];
|
const NAVS = ['group', 'chat', 'organization', 'message'];
|
||||||
|
|
||||||
|
@ -27,79 +50,170 @@ export class DefaultLayoutComponent implements OnInit, OnDestroy {
|
||||||
@ViewChild('leftSidenav', { static: true })
|
@ViewChild('leftSidenav', { static: true })
|
||||||
leftSidenav: MatSidenav;
|
leftSidenav: MatSidenav;
|
||||||
|
|
||||||
|
isShowLeftSideNav = false;
|
||||||
|
|
||||||
|
@ViewChild('profileMenuTrigger', { static: true })
|
||||||
|
profileMenuTrigger: MatMenuTrigger;
|
||||||
|
|
||||||
showStatusbar = true;
|
showStatusbar = true;
|
||||||
|
|
||||||
|
tabIndex: string;
|
||||||
|
queryParams: Params;
|
||||||
|
|
||||||
|
unreadCountChat = 0;
|
||||||
|
|
||||||
/** FAB */
|
/** FAB */
|
||||||
fabButtonShow = true;
|
fabButtonShow = true;
|
||||||
|
fabUseCustomDefaultIcon = true; // default in this prj
|
||||||
fabButtons: { icon: string; tooltip?: string; divisionType?: string }[];
|
fabButtons: { icon: string; tooltip?: string; divisionType?: string }[];
|
||||||
|
versionInfo2Res: VersionInfo2Response;
|
||||||
|
user: User;
|
||||||
|
|
||||||
private windowSizeSubscription: Subscription;
|
moment = moment;
|
||||||
|
|
||||||
|
private ngOnDestroySubject: Subject<void> = new Subject();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private router: Router,
|
private router: Router,
|
||||||
|
private activatedRoute: ActivatedRoute,
|
||||||
private store: Store<any>,
|
private store: Store<any>,
|
||||||
|
private appAccountService: AppAccountService,
|
||||||
private appChatService: AppChatService,
|
private appChatService: AppChatService,
|
||||||
private logService: LogService
|
private logService: LogService,
|
||||||
) {}
|
public dialog: MatDialog
|
||||||
|
) {
|
||||||
|
this.setFabInitial(NAVS[0]);
|
||||||
|
this.router.events
|
||||||
|
.pipe(
|
||||||
|
takeUntil(this.ngOnDestroySubject),
|
||||||
|
filter((event) => event instanceof RouterEvent)
|
||||||
|
)
|
||||||
|
.subscribe((event) => {
|
||||||
|
switch (event.constructor) {
|
||||||
|
case NavigationEnd:
|
||||||
|
{
|
||||||
|
const t = this.router.parseUrl((event as NavigationEnd).url);
|
||||||
|
const p = t.root.children[PRIMARY_OUTLET];
|
||||||
|
if (!p || !p.segments || 0 === p.segments.length) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const index = p.segments[0].path;
|
||||||
|
this.setTabGroup(index);
|
||||||
|
this.setFabInitial(index);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.activatedRoute.queryParams
|
||||||
|
.pipe(takeUntil(this.ngOnDestroySubject))
|
||||||
|
.subscribe((params) => {
|
||||||
|
this.queryParams = params;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.store
|
||||||
|
.pipe(
|
||||||
|
takeUntil(this.ngOnDestroySubject),
|
||||||
|
select(ConfigurationSelector.versionInfo2Response)
|
||||||
|
)
|
||||||
|
.subscribe((versionInfo2Res) => {
|
||||||
|
this.versionInfo2Res = versionInfo2Res;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.windowSizeSubscription = this.store
|
this.store
|
||||||
.pipe(select(AppSelector.windowSize))
|
.pipe(takeUntil(this.ngOnDestroySubject), select(AppSelector.windowSize))
|
||||||
.subscribe((size) => {
|
.subscribe((size) => {
|
||||||
if (size.width < 780) {
|
if (size.width < 780) {
|
||||||
if (this.leftSidenav.opened) {
|
if (this.leftSidenav.opened) {
|
||||||
this.leftSidenav.close();
|
this.leftSidenav.close();
|
||||||
}
|
}
|
||||||
|
this.isShowLeftSideNav = false;
|
||||||
|
this.leftSidenav.mode = 'over';
|
||||||
} else {
|
} else {
|
||||||
if (!this.leftSidenav.opened) {
|
if (!this.leftSidenav.opened) {
|
||||||
this.leftSidenav.open();
|
this.leftSidenav.open();
|
||||||
}
|
}
|
||||||
|
this.isShowLeftSideNav = true;
|
||||||
|
this.leftSidenav.mode = 'side';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.setTabGroup(this.router.url);
|
this.store
|
||||||
|
.pipe(takeUntil(this.ngOnDestroySubject), select(UserSelector.user))
|
||||||
|
.subscribe((user) => {
|
||||||
|
this.user = user;
|
||||||
|
});
|
||||||
|
|
||||||
this.setFabInitial(NAVS[0]);
|
this.store
|
||||||
|
.pipe(
|
||||||
|
takeUntil(this.ngOnDestroySubject),
|
||||||
|
select(RoomSelector.unreadTotal)
|
||||||
|
)
|
||||||
|
.subscribe((unreadTotal) => {
|
||||||
|
this.unreadCountChat = unreadTotal;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
if (!this.windowSizeSubscription) {
|
if (!!this.ngOnDestroySubject) {
|
||||||
this.windowSizeSubscription.unsubscribe();
|
this.ngOnDestroySubject.next();
|
||||||
|
this.ngOnDestroySubject.complete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onOpenProfile(userInfo: UserInfoSS) {
|
||||||
|
this.profileMenuTrigger.openMenu();
|
||||||
|
}
|
||||||
|
|
||||||
onSelectedTabChange(event: MatTabChangeEvent) {
|
onSelectedTabChange(event: MatTabChangeEvent) {
|
||||||
if (4 === event.index) {
|
const commands: any = [
|
||||||
this.router.navigate(
|
|
||||||
['group', { outlets: { content: 'chat/index' } }],
|
|
||||||
{}
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.router.navigate([
|
|
||||||
NAVS[event.index],
|
NAVS[event.index],
|
||||||
{ outlets: { content: 'index' } }
|
{ outlets: { content: 'index' } }
|
||||||
]);
|
];
|
||||||
|
const orgInitialParams: Params = {};
|
||||||
|
|
||||||
|
if (
|
||||||
|
event.index === 1 && // is chat.
|
||||||
|
!!this.queryParams &&
|
||||||
|
!!this.queryParams[ChatQueryParams.ROOM_ID]
|
||||||
|
) {
|
||||||
|
// 다른 화면에서 채팅으로 바로 유입할 경우에는 navigate 초기화를 무시한다.
|
||||||
|
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) {
|
||||||
|
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.setFabInitial(NAVS[event.index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
onClickToggleLeftSidenav() {
|
onClickToggleLeftSidenav() {
|
||||||
if (this.leftSidenav.opened) {
|
if (!this.isShowLeftSideNav) {
|
||||||
this.leftSidenav.close();
|
this.leftSidenav.toggle();
|
||||||
} else {
|
|
||||||
this.leftSidenav.open();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private setTabGroup(url: string) {
|
|
||||||
if (!!this.navTabGroup) {
|
|
||||||
this.navTabGroup.selectedIndex = NAVS.findIndex((v) =>
|
|
||||||
url.startsWith(`/${v}`)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setFabInitial(type: string) {
|
setFabInitial(type: string) {
|
||||||
|
this.tabIndex = type;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'group':
|
case 'group':
|
||||||
{
|
{
|
||||||
|
@ -172,7 +286,20 @@ export class DefaultLayoutComponent implements OnInit, OnDestroy {
|
||||||
switch (btn.divisionType) {
|
switch (btn.divisionType) {
|
||||||
case 'GROUP_NEW_ADD':
|
case 'GROUP_NEW_ADD':
|
||||||
{
|
{
|
||||||
this.logService.debug('GROUP_NEW_ADD');
|
const dialogRef = this.dialog.open(CreateDialogComponent, {
|
||||||
|
panelClass: 'max-create-dialog'
|
||||||
|
});
|
||||||
|
|
||||||
|
dialogRef
|
||||||
|
.afterClosed()
|
||||||
|
.pipe(
|
||||||
|
take(1),
|
||||||
|
map((result) => {}),
|
||||||
|
catchError((err) => {
|
||||||
|
return of(err);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.subscribe();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'CAHT_NEW_ADD':
|
case 'CAHT_NEW_ADD':
|
||||||
|
@ -195,4 +322,37 @@ export class DefaultLayoutComponent implements OnInit, OnDestroy {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onClickSearch(event: Event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
onSelectedProfileManage() {
|
||||||
|
this.profileMenuTrigger.closeMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
onSelectedNotice() {
|
||||||
|
this.profileMenuTrigger.closeMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
onSelectedSettings() {
|
||||||
|
this.profileMenuTrigger.closeMenu();
|
||||||
|
this.appAccountService.dialogForSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
onSelectedLogout() {
|
||||||
|
this.router.navigate(['/account/logout']);
|
||||||
|
}
|
||||||
|
|
||||||
|
onSelectedExit() {}
|
||||||
|
|
||||||
|
onDoneForProfileMenu() {
|
||||||
|
this.profileMenuTrigger.closeMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
private setTabGroup(url: string) {
|
||||||
|
if (!!this.navTabGroup) {
|
||||||
|
this.navTabGroup.selectedIndex = NAVS.findIndex((v) => url === v);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { DefaultLayoutComponent } from './default.layout.component';
|
||||||
import { NoNaviLayoutComponent } from './no-navi.layout.component';
|
import { NoNaviLayoutComponent } from './no-navi.layout.component';
|
||||||
|
|
||||||
import { DefaultDialogLayoutComponent } from './default-dialog.layout.component';
|
import { DefaultDialogLayoutComponent } from './default-dialog.layout.component';
|
||||||
|
import { DefaultDrawerLayoutComponent } from './default-drawer.layout.component';
|
||||||
import { SelectorLayoutComponent } from './selector.layout.component';
|
import { SelectorLayoutComponent } from './selector.layout.component';
|
||||||
|
|
||||||
export const COMPONENTS = [
|
export const COMPONENTS = [
|
||||||
|
@ -12,6 +13,7 @@ export const COMPONENTS = [
|
||||||
NoNaviLayoutComponent,
|
NoNaviLayoutComponent,
|
||||||
|
|
||||||
DefaultDialogLayoutComponent,
|
DefaultDialogLayoutComponent,
|
||||||
|
DefaultDrawerLayoutComponent,
|
||||||
|
|
||||||
SelectorLayoutComponent
|
SelectorLayoutComponent
|
||||||
];
|
];
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
.layout-container {
|
.layout-container {
|
||||||
|
background-color: #f3f4f5;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,9 +9,10 @@
|
||||||
matSuffix
|
matSuffix
|
||||||
aria-label="Clear"
|
aria-label="Clear"
|
||||||
class="btn-close"
|
class="btn-close"
|
||||||
color="accent"
|
color="primary"
|
||||||
|
(click)="onClickClose($event)"
|
||||||
>
|
>
|
||||||
<mat-icon>highlight_off</mat-icon>
|
<mat-icon>close</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="selector-contents">
|
<div class="selector-contents">
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
.selector {
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
.selector-title {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0 5px 0 16px;
|
||||||
|
//border-top: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
.selector-contents {
|
||||||
|
background-color: #fff;
|
||||||
|
border-top: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
.footer {
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,9 +2,10 @@ import {
|
||||||
Component,
|
Component,
|
||||||
OnInit,
|
OnInit,
|
||||||
OnDestroy,
|
OnDestroy,
|
||||||
Input,
|
|
||||||
ChangeDetectionStrategy,
|
ChangeDetectionStrategy,
|
||||||
ChangeDetectorRef
|
ChangeDetectorRef,
|
||||||
|
EventEmitter,
|
||||||
|
Output
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -14,9 +15,16 @@ import {
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class SelectorLayoutComponent implements OnInit, OnDestroy {
|
export class SelectorLayoutComponent implements OnInit, OnDestroy {
|
||||||
|
@Output()
|
||||||
|
closed = new EventEmitter<void>();
|
||||||
|
|
||||||
constructor(private changeDetectorRef: ChangeDetectorRef) {}
|
constructor(private changeDetectorRef: ChangeDetectorRef) {}
|
||||||
|
|
||||||
ngOnInit(): void {}
|
ngOnInit(): void {}
|
||||||
|
|
||||||
ngOnDestroy(): void {}
|
ngOnDestroy(): void {}
|
||||||
|
|
||||||
|
onClickClose(event: MouseEvent): void {
|
||||||
|
this.closed.emit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<div class="title-bar">
|
<div class="title-bar">
|
||||||
<ucap-title-bar
|
<ucap-title-bar
|
||||||
[platform]="platform"
|
[platform]="platform"
|
||||||
[native]="native"
|
|
||||||
(closed)="onClosedTitleBar()"
|
(closed)="onClosedTitleBar()"
|
||||||
(maximized)="onMaximizedTitleBar()"
|
(maximized)="onMaximizedTitleBar()"
|
||||||
(minimized)="onMinimizedTitleBar()"
|
(minimized)="onMinimizedTitleBar()"
|
||||||
>
|
>
|
||||||
|
<ng-content></ng-content>
|
||||||
</ucap-title-bar>
|
</ucap-title-bar>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,5 +2,5 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
background-color: #ffffff;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,16 @@
|
||||||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
import { Subject } from 'rxjs';
|
||||||
|
import { takeUntil } from 'rxjs/operators';
|
||||||
|
|
||||||
|
import { Component, OnInit, OnDestroy, Inject } from '@angular/core';
|
||||||
|
|
||||||
|
import * as detectBrowser from 'detect-browser';
|
||||||
|
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
|
|
||||||
|
import { NativeService, WindowState, NativeType } from '@ucap/native';
|
||||||
|
|
||||||
|
import { UCAP_NATIVE_SERVICE } from '@ucap/ng-native';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-layouts-top-bar',
|
selector: 'app-layouts-top-bar',
|
||||||
templateUrl: './top-bar.component.html',
|
templateUrl: './top-bar.component.html',
|
||||||
|
@ -9,13 +18,54 @@ import { Store } from '@ngrx/store';
|
||||||
})
|
})
|
||||||
export class TopBarComponent implements OnInit, OnDestroy {
|
export class TopBarComponent implements OnInit, OnDestroy {
|
||||||
platform = 'win32';
|
platform = 'win32';
|
||||||
native = true;
|
windowState: WindowState;
|
||||||
|
|
||||||
constructor(private store: Store<any>) {}
|
private ngOnDestroySubject: Subject<void> = new Subject();
|
||||||
|
|
||||||
ngOnInit() {}
|
constructor(
|
||||||
|
@Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService,
|
||||||
|
private store: Store<any>
|
||||||
|
) {
|
||||||
|
this.nativeService.platform_nativeType().then((type) => {
|
||||||
|
switch (type) {
|
||||||
|
case NativeType.Browser:
|
||||||
|
this.platform = 'browser';
|
||||||
|
break;
|
||||||
|
case NativeType.Electron:
|
||||||
|
{
|
||||||
|
const info = detectBrowser.detect();
|
||||||
|
if (info.os.startsWith('Windows')) {
|
||||||
|
this.platform = 'win32';
|
||||||
|
} else if (info.os.startsWith('Mac OS')) {
|
||||||
|
this.platform = 'darwin';
|
||||||
|
} else if (info.os.startsWith('Linux')) {
|
||||||
|
this.platform = 'linux';
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
ngOnDestroy(): void {}
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.nativeService
|
||||||
|
.window_onState$()
|
||||||
|
.pipe(takeUntil(this.ngOnDestroySubject))
|
||||||
|
.subscribe((windowState) => {
|
||||||
|
this.windowState = windowState;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
if (!!this.ngOnDestroySubject) {
|
||||||
|
this.ngOnDestroySubject.next();
|
||||||
|
this.ngOnDestroySubject.complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onClosedTitleBar() {}
|
onClosedTitleBar() {}
|
||||||
|
|
||||||
|
|
|
@ -5,21 +5,25 @@ import { RouterModule } from '@angular/router';
|
||||||
|
|
||||||
import { FlexLayoutModule } from '@angular/flex-layout';
|
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||||
|
|
||||||
|
import { MatBadgeModule } from '@angular/material/badge';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
|
import { MatMenuModule } from '@angular/material/menu';
|
||||||
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
import { MatSidenavModule } from '@angular/material/sidenav';
|
import { MatSidenavModule } from '@angular/material/sidenav';
|
||||||
import { MatTabsModule } from '@angular/material/tabs';
|
import { MatTabsModule } from '@angular/material/tabs';
|
||||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||||
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||||
|
|
||||||
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
|
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
|
||||||
|
|
||||||
|
import { I18nModule, UCAP_I18N_NAMESPACE } from '@ucap/ng-i18n';
|
||||||
import { UiModule } from '@ucap/ng-ui';
|
import { UiModule } from '@ucap/ng-ui';
|
||||||
|
|
||||||
|
import { AppOrganizationModule } from '@app/ucap/organization/organization.module';
|
||||||
|
|
||||||
import { COMPONENTS } from './components';
|
import { COMPONENTS } from './components';
|
||||||
import { DIALOGS } from './dialogs';
|
import { DIALOGS } from './dialogs';
|
||||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
||||||
import { I18nModule, UCAP_I18N_NAMESPACE } from '@ucap/ng-i18n';
|
|
||||||
import { MatSelectModule } from '@angular/material/select';
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -28,17 +32,22 @@ import { MatSelectModule } from '@angular/material/select';
|
||||||
|
|
||||||
FlexLayoutModule,
|
FlexLayoutModule,
|
||||||
|
|
||||||
|
MatBadgeModule,
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
MatIconModule,
|
MatIconModule,
|
||||||
|
MatMenuModule,
|
||||||
|
MatSelectModule,
|
||||||
MatSidenavModule,
|
MatSidenavModule,
|
||||||
MatTabsModule,
|
MatTabsModule,
|
||||||
MatToolbarModule,
|
MatToolbarModule,
|
||||||
MatSelectModule,
|
MatTooltipModule,
|
||||||
|
|
||||||
PerfectScrollbarModule,
|
PerfectScrollbarModule,
|
||||||
|
|
||||||
I18nModule,
|
I18nModule,
|
||||||
UiModule
|
UiModule,
|
||||||
|
|
||||||
|
AppOrganizationModule
|
||||||
],
|
],
|
||||||
exports: [...COMPONENTS, ...DIALOGS],
|
exports: [...COMPONENTS, ...DIALOGS],
|
||||||
declarations: [...COMPONENTS, ...DIALOGS],
|
declarations: [...COMPONENTS, ...DIALOGS],
|
||||||
|
@ -46,7 +55,7 @@ import { MatSelectModule } from '@angular/material/select';
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
provide: UCAP_I18N_NAMESPACE,
|
provide: UCAP_I18N_NAMESPACE,
|
||||||
useValue: ['chat', 'common']
|
useValue: ['common']
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
4
src/app/models/group-open-info.ts
Normal file
4
src/app/models/group-open-info.ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
export interface GroupOpenInfo {
|
||||||
|
lastGroupSeq: number;
|
||||||
|
groupSeqs: number[];
|
||||||
|
}
|
|
@ -1,8 +1,10 @@
|
||||||
import { LoginSession as UCAPLoginSession } from '@ucap/core';
|
import { LoginSession as UCAPLoginSession } from '@ucap/core';
|
||||||
|
import { GroupOpenInfo } from './group-open-info';
|
||||||
|
|
||||||
export interface LoginSession extends UCAPLoginSession {
|
export interface LoginSession extends UCAPLoginSession {
|
||||||
loginPw?: string;
|
loginPw?: string;
|
||||||
initPw?: boolean;
|
initPw?: boolean;
|
||||||
encData?: string;
|
encData?: string;
|
||||||
alive?: boolean;
|
alive?: boolean;
|
||||||
|
groupInfo?: GroupOpenInfo;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { Routes, RouterModule } from '@angular/router';
|
||||||
|
|
||||||
import { ForgotPasswordPageComponent } from './components/forgot-password.page.component';
|
import { ForgotPasswordPageComponent } from './components/forgot-password.page.component';
|
||||||
import { LoginPageComponent } from './components/login.page.component';
|
import { LoginPageComponent } from './components/login.page.component';
|
||||||
|
import { LogoutPageComponent } from './components/logout.page.component';
|
||||||
import { ResetPasswordPageComponent } from './components/reset-password.page.component';
|
import { ResetPasswordPageComponent } from './components/reset-password.page.component';
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
|
@ -17,6 +18,10 @@ const routes: Routes = [
|
||||||
{
|
{
|
||||||
path: 'reset_password',
|
path: 'reset_password',
|
||||||
component: ResetPasswordPageComponent
|
component: ResetPasswordPageComponent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'logout',
|
||||||
|
component: LogoutPageComponent
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -25,13 +25,11 @@ export class LoginPageComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
readonly fixedCompanyCode = environment.companyConfig.fixedCompanyCode;
|
readonly fixedCompanyCode = environment.companyConfig.fixedCompanyCode;
|
||||||
|
|
||||||
private ngOnDestroySubject = new Subject<boolean>();
|
private ngOnDestroySubject: Subject<void> = new Subject();
|
||||||
|
|
||||||
constructor(private localStorageService: LocalStorageService) {}
|
constructor(private localStorageService: LocalStorageService) {}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.ngOnDestroySubject = new Subject<boolean>();
|
|
||||||
|
|
||||||
this.localStorageService
|
this.localStorageService
|
||||||
.encGet$<UserStore>(
|
.encGet$<UserStore>(
|
||||||
AppKey.UserStore,
|
AppKey.UserStore,
|
||||||
|
@ -43,6 +41,7 @@ export class LoginPageComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
if (!!this.ngOnDestroySubject) {
|
if (!!this.ngOnDestroySubject) {
|
||||||
|
this.ngOnDestroySubject.next();
|
||||||
this.ngOnDestroySubject.complete();
|
this.ngOnDestroySubject.complete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
<div class="logout-container">Logout</div>
|
|
@ -0,0 +1,6 @@
|
||||||
|
@import '~@ucap/lg-scss/mixins';
|
||||||
|
|
||||||
|
.logout-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
|
@ -1,28 +1,28 @@
|
||||||
import { TestBed, async } from '@angular/core/testing';
|
import { TestBed, async } from '@angular/core/testing';
|
||||||
import { RouterTestingModule } from '@angular/router/testing';
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
import { LoginSectionComponent } from './login.section.component';
|
import { LogoutPageComponent } from './logout.page.component';
|
||||||
|
|
||||||
describe('app::sections::account::LoginSectionComponent', () => {
|
describe('app::pages::account::LogoutPageComponent', () => {
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [RouterTestingModule],
|
imports: [RouterTestingModule],
|
||||||
declarations: [LoginSectionComponent]
|
declarations: [LogoutPageComponent]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should create the app', () => {
|
it('should create the app', () => {
|
||||||
const fixture = TestBed.createComponent(LoginSectionComponent);
|
const fixture = TestBed.createComponent(LogoutPageComponent);
|
||||||
const app = fixture.componentInstance;
|
const app = fixture.componentInstance;
|
||||||
expect(app).toBeTruthy();
|
expect(app).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should have as title 'ucap-lg-web'`, () => {
|
it(`should have as title 'ucap-lg-web'`, () => {
|
||||||
const fixture = TestBed.createComponent(LoginSectionComponent);
|
const fixture = TestBed.createComponent(LogoutPageComponent);
|
||||||
const app = fixture.componentInstance;
|
const app = fixture.componentInstance;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render title', () => {
|
it('should render title', () => {
|
||||||
const fixture = TestBed.createComponent(LoginSectionComponent);
|
const fixture = TestBed.createComponent(LogoutPageComponent);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
const compiled = fixture.nativeElement;
|
const compiled = fixture.nativeElement;
|
||||||
expect(compiled.querySelector('.content span').textContent).toContain(
|
expect(compiled.querySelector('.content span').textContent).toContain(
|
30
src/app/pages/account/components/logout.page.component.ts
Normal file
30
src/app/pages/account/components/logout.page.component.ts
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||||
|
|
||||||
|
import { LocalStorageService } from '@ucap/ng-web-storage';
|
||||||
|
|
||||||
|
import { environment } from '@environments';
|
||||||
|
|
||||||
|
import { UserStore } from '@app/models/user-store';
|
||||||
|
import { AppKey } from '@app/types/app-key.type';
|
||||||
|
import { Subject } from 'rxjs';
|
||||||
|
import { takeUntil } from 'rxjs/operators';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-pages-account-logout',
|
||||||
|
templateUrl: './logout.page.component.html',
|
||||||
|
styleUrls: ['./logout.page.component.scss']
|
||||||
|
})
|
||||||
|
export class LogoutPageComponent implements OnInit, OnDestroy {
|
||||||
|
private ngOnDestroySubject: Subject<void> = new Subject();
|
||||||
|
|
||||||
|
constructor(private localStorageService: LocalStorageService) {}
|
||||||
|
|
||||||
|
ngOnInit(): void {}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
if (!!this.ngOnDestroySubject) {
|
||||||
|
this.ngOnDestroySubject.next();
|
||||||
|
this.ngOnDestroySubject.complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ import { MatMenuModule } from '@angular/material/menu';
|
||||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatSidenavModule } from '@angular/material/sidenav';
|
import { MatSidenavModule } from '@angular/material/sidenav';
|
||||||
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||||
|
|
||||||
import { AppChatSectionModule } from '@app/sections/chat/chat.section.module';
|
import { AppChatSectionModule } from '@app/sections/chat/chat.section.module';
|
||||||
|
|
||||||
|
@ -27,6 +28,7 @@ import { UCAP_I18N_NAMESPACE, I18nModule } from '@ucap/ng-i18n';
|
||||||
MatCheckboxModule,
|
MatCheckboxModule,
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
MatSidenavModule,
|
MatSidenavModule,
|
||||||
|
MatTooltipModule,
|
||||||
|
|
||||||
AppChatSectionModule,
|
AppChatSectionModule,
|
||||||
AppChatRoutingPageModule,
|
AppChatRoutingPageModule,
|
||||||
|
|
|
@ -3,22 +3,72 @@
|
||||||
<app-sections-chat-info
|
<app-sections-chat-info
|
||||||
[roomId]="roomId"
|
[roomId]="roomId"
|
||||||
(openChatSearch)="isChatSearch = true"
|
(openChatSearch)="isChatSearch = true"
|
||||||
(rightDrawerToggle)="onRightDrawerToggle()"
|
(rightDrawerToggle)="onRightDrawerToggle($event)"
|
||||||
></app-sections-chat-info>
|
></app-sections-chat-info>
|
||||||
</div>
|
</div>
|
||||||
<app-sections-chat-chat-search
|
<app-sections-chat-chat-search
|
||||||
*ngIf="isChatSearch"
|
[isChatSearch]="isChatSearch"
|
||||||
(closeChatSearch)="isChatSearch = false"
|
(closeChatSearch)="isChatSearch = false"
|
||||||
></app-sections-chat-chat-search>
|
></app-sections-chat-chat-search>
|
||||||
<mat-drawer-container autosize fxFlex="1 1 auto" fxLayout="column">
|
<mat-drawer-container autosize fxFlex="1 1 auto" fxLayout="column">
|
||||||
<div class="message-area" fxFlex="1 1 auto">
|
<div class="message-box-container" fxFlex="1 1 auto" fxLayout="column">
|
||||||
<app-sections-chat-message [roomId]="roomId"></app-sections-chat-message>
|
<div class="message-area" fxFlex="1 1 auto">
|
||||||
</div>
|
<app-sections-chat-message
|
||||||
<div class="message-input" fxFlex="0 0 auto">
|
[roomId]="roomId"
|
||||||
<app-sections-chat-form [roomId]="roomId"></app-sections-chat-form>
|
[translationSimpleview]="translationSimpleview"
|
||||||
|
[eventSendTrigger$]="eventSendTriggerSubject.asObservable()"
|
||||||
|
></app-sections-chat-message>
|
||||||
|
</div>
|
||||||
|
<div class="message-input" fxFlex="0 0 auto">
|
||||||
|
<app-sections-chat-form
|
||||||
|
[roomId]="roomId"
|
||||||
|
(changeTranslationSimpleview)="translationSimpleview = $event"
|
||||||
|
(eventSendTrigger)="eventSendTriggerSubject.next($event)"
|
||||||
|
></app-sections-chat-form>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<mat-drawer #chatRightDrawer mode="side" position="end" class="rightDrawer">
|
<mat-drawer #chatRightDrawer mode="side" position="end" class="rightDrawer">
|
||||||
Right Sections.
|
<ng-container [ngSwitch]="drawerType">
|
||||||
|
<app-drawer-chat-attach-data
|
||||||
|
*ngSwitchCase="
|
||||||
|
[
|
||||||
|
ChatDrawType.AttachImage,
|
||||||
|
ChatDrawType.AttachVideo,
|
||||||
|
ChatDrawType.AttachFile
|
||||||
|
].includes(drawerType)
|
||||||
|
? drawerType
|
||||||
|
: ''
|
||||||
|
"
|
||||||
|
[roomId]="roomId"
|
||||||
|
[drawerType]="drawerType"
|
||||||
|
(closed)="onRightDrawerClose()"
|
||||||
|
></app-drawer-chat-attach-data>
|
||||||
|
<app-drawer-chat-users
|
||||||
|
*ngSwitchCase="ChatDrawType.RoomUsers"
|
||||||
|
[roomId]="roomId"
|
||||||
|
(closed)="onRightDrawerClose()"
|
||||||
|
(rightDrawerToggle)="onRightDrawerToggle($event)"
|
||||||
|
></app-drawer-chat-users>
|
||||||
|
<app-drawer-chat-add-users
|
||||||
|
*ngSwitchCase="ChatDrawType.Invite"
|
||||||
|
[roomId]="roomId"
|
||||||
|
[returnChatDrawerType]="returnDrawerType"
|
||||||
|
(closed)="onRightDrawerClose()"
|
||||||
|
(rightDrawerToggle)="onRightDrawerToggle($event)"
|
||||||
|
></app-drawer-chat-add-users>
|
||||||
|
<app-drawer-chat-add-group
|
||||||
|
*ngSwitchCase="ChatDrawType.AddGroup"
|
||||||
|
[roomId]="roomId"
|
||||||
|
[returnChatDrawerType]="returnDrawerType"
|
||||||
|
(closed)="onRightDrawerClose()"
|
||||||
|
(rightDrawerToggle)="onRightDrawerToggle($event)"
|
||||||
|
></app-drawer-chat-add-group>
|
||||||
|
<app-drawer-chat-setting
|
||||||
|
*ngSwitchCase="ChatDrawType.Setting"
|
||||||
|
[roomId]="roomId"
|
||||||
|
(closed)="onRightDrawerClose()"
|
||||||
|
></app-drawer-chat-setting>
|
||||||
|
</ng-container>
|
||||||
</mat-drawer>
|
</mat-drawer>
|
||||||
</mat-drawer-container>
|
</mat-drawer-container>
|
||||||
</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%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,8 +3,13 @@ import { ActivatedRoute, Params } from '@angular/router';
|
||||||
|
|
||||||
import { MatDrawer } from '@angular/material/sidenav';
|
import { MatDrawer } from '@angular/material/sidenav';
|
||||||
|
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription, Subject, BehaviorSubject } from 'rxjs';
|
||||||
import { QueryParams } from '../types/params.type';
|
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';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-pages-chat-room',
|
selector: 'app-pages-chat-room',
|
||||||
|
@ -12,30 +17,65 @@ import { QueryParams } from '../types/params.type';
|
||||||
styleUrls: ['./chat-room.page.component.scss']
|
styleUrls: ['./chat-room.page.component.scss']
|
||||||
})
|
})
|
||||||
export class ChatRoomPageComponent implements OnInit, OnDestroy {
|
export class ChatRoomPageComponent implements OnInit, OnDestroy {
|
||||||
private paramsSubscription: Subscription;
|
|
||||||
isChatSearch = false;
|
isChatSearch = false;
|
||||||
roomId: string;
|
roomId: string;
|
||||||
|
translationSimpleview = false;
|
||||||
|
|
||||||
|
drawerType: ChatDrawType | null;
|
||||||
|
returnDrawerType: ChatDrawType | null;
|
||||||
|
eventSendTriggerSubject: BehaviorSubject<any> = new BehaviorSubject<any>(0);
|
||||||
|
|
||||||
@ViewChild('chatRightDrawer', { static: false })
|
@ViewChild('chatRightDrawer', { static: false })
|
||||||
chatRightDrawer: MatDrawer;
|
chatRightDrawer: MatDrawer;
|
||||||
|
|
||||||
constructor(private activatedRoute: ActivatedRoute) {}
|
ChatDrawType = ChatDrawType;
|
||||||
|
|
||||||
|
private ngOnDestroySubject: Subject<void> = new Subject();
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private store: Store<any>,
|
||||||
|
private activatedRoute: ActivatedRoute
|
||||||
|
) {}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.paramsSubscription = this.activatedRoute.queryParams.subscribe(
|
this.activatedRoute.queryParams
|
||||||
(params: Params) => {
|
.pipe(takeUntil(this.ngOnDestroySubject))
|
||||||
|
.subscribe((params: Params) => {
|
||||||
const seqParam = params[QueryParams.ROOM_ID];
|
const seqParam = params[QueryParams.ROOM_ID];
|
||||||
|
// initializing by roomId Change.
|
||||||
|
if (this.roomId !== seqParam) {
|
||||||
|
if (!!this.chatRightDrawer) {
|
||||||
|
this.chatRightDrawer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// setting roomId.
|
||||||
this.roomId = !!seqParam ? seqParam : undefined;
|
this.roomId = !!seqParam ? seqParam : undefined;
|
||||||
}
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
if (!!this.paramsSubscription) {
|
if (!!this.ngOnDestroySubject) {
|
||||||
this.paramsSubscription.unsubscribe();
|
this.ngOnDestroySubject.next();
|
||||||
|
this.ngOnDestroySubject.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!!this.eventSendTriggerSubject) {
|
||||||
|
this.eventSendTriggerSubject.complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
// this.store.dispatch(RoomActions.clearSelectedRoom({ roomId: this.roomId }));
|
||||||
|
this.store.dispatch(ChattingActions.clearActiveRoomId({}));
|
||||||
}
|
}
|
||||||
onRightDrawerToggle(): void {
|
|
||||||
this.chatRightDrawer.toggle();
|
onRightDrawerToggle(type: DrawInfo | null): void {
|
||||||
|
this.drawerType = type.chatDrawType;
|
||||||
|
this.returnDrawerType = !!type.returnDrawType ? type.returnDrawType : null;
|
||||||
|
this.chatRightDrawer.open();
|
||||||
|
}
|
||||||
|
onRightDrawerClose(): void {
|
||||||
|
this.drawerType = null;
|
||||||
|
this.returnDrawerType = null;
|
||||||
|
this.chatRightDrawer.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1,39 @@
|
||||||
Index page of chat is works!
|
<div class="index-page-chat-info">
|
||||||
|
<div class="ico-page-chat">
|
||||||
|
<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="chat-index-copy">
|
||||||
|
{{ 'chat:room.noSelectRoom' | ucapI18n }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
.index-page-chat-info {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
.ico-page-chat {
|
||||||
|
width: 166px;
|
||||||
|
height: 142px;
|
||||||
|
margin-top: -80px;
|
||||||
|
}
|
||||||
|
.chat-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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,13 +1,41 @@
|
||||||
<div fxFlexFill class="sidenav-container">
|
<div fxFlexFill class="sidenav-container">
|
||||||
<div class="chat-header">
|
<div class="chat-header">
|
||||||
<h3>{{ 'label.chat' | ucapI18n }}</h3>
|
<h3>{{ 'chat:label.chat' | ucapI18n }}</h3>
|
||||||
<div class="chat-menu-btn">
|
<div class="chat-menu-btn">
|
||||||
<button
|
<button
|
||||||
mat-icon-button
|
mat-icon-button
|
||||||
aria-label="exit-room"
|
aria-label="exit-room"
|
||||||
|
[matTooltip]="'chat:label.exitFromRoom' | ucapI18n"
|
||||||
(click)="onToggleChackable(true)"
|
(click)="onToggleChackable(true)"
|
||||||
>
|
>
|
||||||
<mat-icon>exit_to_app</mat-icon>
|
<mat-icon>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<g transform="translate(-1)">
|
||||||
|
<path
|
||||||
|
d="M0 0h24v24H0z"
|
||||||
|
transform="translate(1)"
|
||||||
|
style="fill: none;"
|
||||||
|
/>
|
||||||
|
<g transform="translate(3 3)">
|
||||||
|
<path
|
||||||
|
d="M8.963 3h8.693a1.962 1.962 0 0 1 1.963 1.963v3.926h-1.963V4.963H8.963V18.7h8.693v-3.922h1.963V18.7a1.962 1.962 0 0 1-1.963 1.963H8.963A1.969 1.969 0 0 1 7 18.7V4.963A1.969 1.969 0 0 1 8.963 3z"
|
||||||
|
style="fill: #666;"
|
||||||
|
transform="translate(-7 -3)"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M13.459 14.542l1.384 1.384 4.907-4.907-4.907-4.908-1.384 1.384 2.532 2.542H6.5V12h9.491z"
|
||||||
|
style="fill: #666;"
|
||||||
|
transform="translate(-.19 -2.326)"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
mat-icon-button
|
mat-icon-button
|
||||||
|
@ -25,15 +53,19 @@
|
||||||
[style.display]="checkable ? 'none' : 'block'"
|
[style.display]="checkable ? 'none' : 'block'"
|
||||||
></app-sections-chat-search>
|
></app-sections-chat-search>
|
||||||
<div class="exitRoomInfo" *ngIf="checkable">
|
<div class="exitRoomInfo" *ngIf="checkable">
|
||||||
<div>
|
<div class="chat-exit-info">
|
||||||
<strong>{{ this.selectedRoomList.length }}</strong
|
{{ 'chat:label.exitFromRoom' | ucapI18n }}
|
||||||
>/{{
|
<span
|
||||||
!!this.searchObj.isShowSearch
|
>( <strong>{{ this.selectedRoomList.length }}</strong
|
||||||
? this.searchResultList.length
|
>/{{
|
||||||
: this.roomList.length
|
!!this.searchObj.isShowSearch
|
||||||
}}
|
? this.searchResultList.length
|
||||||
|
: this.roomList.length
|
||||||
|
}}
|
||||||
|
)</span
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div class="chat-exit-checkbox">
|
||||||
<mat-checkbox
|
<mat-checkbox
|
||||||
#allCheck
|
#allCheck
|
||||||
aria-label="all select exit room "
|
aria-label="all select exit room "
|
||||||
|
@ -41,7 +73,6 @@
|
||||||
(change)="onToggleAllItem(allCheck.checked)"
|
(change)="onToggleAllItem(allCheck.checked)"
|
||||||
(click)="$event.stopPropagation()"
|
(click)="$event.stopPropagation()"
|
||||||
>
|
>
|
||||||
전체선택
|
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
@import '~@ucap/lg-scss/mixins';
|
||||||
|
|
||||||
|
.sidenav-container {
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
align-content: flex-start;
|
||||||
|
background-color: #f1f2f6;
|
||||||
|
.chat-header {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0 5px 0 17px;
|
||||||
|
background-color: $white;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
h3 {
|
||||||
|
@include font-family-txt(18, left, $lipstick);
|
||||||
|
align-items: center;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.chat-menu-btn {
|
||||||
|
justify-self: end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.exitRoomInfo {
|
||||||
|
height: 50px;
|
||||||
|
min-height: 50px;
|
||||||
|
max-height: 50px;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0 17px;
|
||||||
|
background-color: $white;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
.chat-exit-info {
|
||||||
|
font-size: 1em;
|
||||||
|
color: $gray-re3;
|
||||||
|
@include font-family($font-semibold, normal);
|
||||||
|
font-weight: 600;
|
||||||
|
span {
|
||||||
|
color: $gray-re9;
|
||||||
|
strong {
|
||||||
|
color: $lipstick;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.chat-exit-checkbox {
|
||||||
|
justify-self: self-end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,6 +13,12 @@ import {
|
||||||
ConfirmDialogResult
|
ConfirmDialogResult
|
||||||
} from '@ucap/ng-ui';
|
} from '@ucap/ng-ui';
|
||||||
import { I18nService } from '@ucap/ng-i18n';
|
import { I18nService } from '@ucap/ng-i18n';
|
||||||
|
import { SearchInfo } from '../models/search-info';
|
||||||
|
import { ActivatedRoute, Params } from '@angular/router';
|
||||||
|
import { QueryParams } from '../types/params.type';
|
||||||
|
import { AppChatService } from '@app/services/app-chat.service';
|
||||||
|
import { SessionStorageService } from '@ucap/ng-web-storage';
|
||||||
|
import { AppKey } from '@app/types';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-pages-chat-sidenav',
|
selector: 'app-pages-chat-sidenav',
|
||||||
|
@ -20,32 +26,56 @@ import { I18nService } from '@ucap/ng-i18n';
|
||||||
styleUrls: ['./sidenav.page.component.scss']
|
styleUrls: ['./sidenav.page.component.scss']
|
||||||
})
|
})
|
||||||
export class SidenavPageComponent implements OnInit, OnDestroy {
|
export class SidenavPageComponent implements OnInit, OnDestroy {
|
||||||
searchObj: any = {
|
searchObj: SearchInfo = {
|
||||||
isShowSearch: false,
|
isShowSearch: false,
|
||||||
searchWord: ''
|
searchWord: ''
|
||||||
};
|
};
|
||||||
|
|
||||||
checkable = false;
|
checkable = false;
|
||||||
|
|
||||||
|
historyRoomId: string;
|
||||||
|
|
||||||
roomList: RoomInfo[];
|
roomList: RoomInfo[];
|
||||||
selectedRoomList: RoomInfo[] = [];
|
selectedRoomList: RoomInfo[] = [];
|
||||||
searchResultList: RoomInfo[] = [];
|
searchResultList: RoomInfo[] = [];
|
||||||
|
|
||||||
private ngOnDestroySubject: Subject<boolean>;
|
private ngOnDestroySubject: Subject<void> = new Subject();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private store: Store<any>,
|
private store: Store<any>,
|
||||||
private dialog: MatDialog,
|
private dialog: MatDialog,
|
||||||
private i18nService: I18nService,
|
private i18nService: I18nService,
|
||||||
private logService: LogService,
|
private logService: LogService,
|
||||||
|
private sessionStorageService: SessionStorageService,
|
||||||
|
private activatedRoute: ActivatedRoute,
|
||||||
|
private appChatService: AppChatService,
|
||||||
private changeDetectorRef: ChangeDetectorRef
|
private changeDetectorRef: ChangeDetectorRef
|
||||||
) {}
|
) {
|
||||||
|
this.historyRoomId = this.sessionStorageService.get<string>(
|
||||||
|
AppKey.HistoryRoomId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.ngOnDestroySubject = new Subject<boolean>();
|
this.activatedRoute.queryParams
|
||||||
|
.pipe(takeUntil(this.ngOnDestroySubject))
|
||||||
|
.subscribe((params: Params) => {
|
||||||
|
const seqParam = params[QueryParams.ROOM_ID];
|
||||||
|
|
||||||
// language setting
|
this.sessionStorageService.set<string>(
|
||||||
this.i18nService.setDefaultNamespace('chat');
|
AppKey.HistoryRoomId,
|
||||||
|
!!seqParam ? seqParam : undefined
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
seqParam === undefined &&
|
||||||
|
!!this.historyRoomId &&
|
||||||
|
this.historyRoomId.length > 0
|
||||||
|
) {
|
||||||
|
// exist history roomId.
|
||||||
|
this.appChatService.openRoombyRoomId(this.historyRoomId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.store
|
this.store
|
||||||
.pipe(takeUntil(this.ngOnDestroySubject), select(RoomSelector.rooms))
|
.pipe(takeUntil(this.ngOnDestroySubject), select(RoomSelector.rooms))
|
||||||
|
@ -57,6 +87,7 @@ export class SidenavPageComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
if (!!this.ngOnDestroySubject) {
|
if (!!this.ngOnDestroySubject) {
|
||||||
|
this.ngOnDestroySubject.next();
|
||||||
this.ngOnDestroySubject.complete();
|
this.ngOnDestroySubject.complete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,14 +95,16 @@ export class SidenavPageComponent implements OnInit, OnDestroy {
|
||||||
onToggleChackable(checkable: boolean): void {
|
onToggleChackable(checkable: boolean): void {
|
||||||
if (!!checkable) {
|
if (!!checkable) {
|
||||||
if (!!this.selectedRoomList && this.selectedRoomList.length > 0) {
|
if (!!this.selectedRoomList && this.selectedRoomList.length > 0) {
|
||||||
|
const self = this;
|
||||||
const dialogRef = this.dialog.open<
|
const dialogRef = this.dialog.open<
|
||||||
ConfirmDialogComponent,
|
ConfirmDialogComponent,
|
||||||
ConfirmDialogData,
|
ConfirmDialogData,
|
||||||
ConfirmDialogResult
|
ConfirmDialogResult
|
||||||
>(ConfirmDialogComponent, {
|
>(ConfirmDialogComponent, {
|
||||||
|
panelClass: 'min-create-dialog',
|
||||||
data: {
|
data: {
|
||||||
title: this.i18nService.t('dialog.title.exitFromRoom'),
|
title: this.i18nService.t('chat:label.exitFromRoom'),
|
||||||
html: this.i18nService.t('dialog.confirmExitFromRoom')
|
html: this.i18nService.t('chat:dialog.confirmExitFromRoom')
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -89,6 +122,8 @@ export class SidenavPageComponent implements OnInit, OnDestroy {
|
||||||
} as ExitAllRequest
|
} as ExitAllRequest
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
self.selectedRoomList = [];
|
||||||
|
self.checkable = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -131,7 +166,7 @@ export class SidenavPageComponent implements OnInit, OnDestroy {
|
||||||
} else {
|
} else {
|
||||||
this.selectedRoomList = [];
|
this.selectedRoomList = [];
|
||||||
}
|
}
|
||||||
this.changeDetectorRef.detectChanges();
|
this.changeDetectorRef.markForCheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
onToggleItem(event: { checked: boolean; roomInfo: RoomInfo }): void {
|
onToggleItem(event: { checked: boolean; roomInfo: RoomInfo }): void {
|
||||||
|
@ -160,16 +195,16 @@ export class SidenavPageComponent implements OnInit, OnDestroy {
|
||||||
this.searchObj = {
|
this.searchObj = {
|
||||||
isShowSearch: true,
|
isShowSearch: true,
|
||||||
searchWord: params.searchWord
|
searchWord: params.searchWord
|
||||||
};
|
} as SearchInfo;
|
||||||
this.changeDetectorRef.detectChanges();
|
this.changeDetectorRef.markForCheck();
|
||||||
}
|
}
|
||||||
/** Searching cancel */
|
/** Searching cancel */
|
||||||
onClickCancel() {
|
onClickCancel() {
|
||||||
this.searchObj = {
|
this.searchObj = {
|
||||||
isShowSearch: false,
|
isShowSearch: false,
|
||||||
searchWord: ''
|
searchWord: ''
|
||||||
};
|
} as SearchInfo;
|
||||||
this.changeDetectorRef.detectChanges();
|
this.changeDetectorRef.markForCheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
onSearchResultList(searchResultList: RoomInfo[]) {
|
onSearchResultList(searchResultList: RoomInfo[]) {
|
||||||
|
|
6
src/app/pages/chat/models/draw-info.ts
Normal file
6
src/app/pages/chat/models/draw-info.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import { ChatDrawType } from '../types/chat-draw.type';
|
||||||
|
|
||||||
|
export interface DrawInfo {
|
||||||
|
chatDrawType: ChatDrawType;
|
||||||
|
returnDrawType?: ChatDrawType;
|
||||||
|
}
|
4
src/app/pages/chat/models/search-info.ts
Normal file
4
src/app/pages/chat/models/search-info.ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
export interface SearchInfo {
|
||||||
|
isShowSearch: boolean;
|
||||||
|
searchWord: string;
|
||||||
|
}
|
9
src/app/pages/chat/types/chat-draw.type.ts
Normal file
9
src/app/pages/chat/types/chat-draw.type.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
export enum ChatDrawType {
|
||||||
|
AttachImage = 'ATTACHIMAGE',
|
||||||
|
AttachVideo = 'ATTACHVIDEO',
|
||||||
|
AttachFile = 'ATTACHFILE',
|
||||||
|
Invite = 'INVITE',
|
||||||
|
Setting = 'SETTING',
|
||||||
|
RoomUsers = 'ROOMUSERS',
|
||||||
|
AddGroup = 'ADDGROUP'
|
||||||
|
}
|
|
@ -1,11 +1,45 @@
|
||||||
<div fxLayout="column" class="index-container">
|
<div fxLayout="column" class="index-container">
|
||||||
<div class="subtitle" fxFlex="60px">Welcome to M-Messenger</div>
|
<!--<div class="subtitle" fxFlex="60px">Welcome to M-Messenger</div>-->
|
||||||
<div class="content-container" fxFlex="1 1 auto" fxLayout="row">
|
<div class="content-container" fxFlex="1 1 auto" fxLayout="row">
|
||||||
<div class="profile-container" fxFlex="44%">
|
<nav mat-tab-nav-bar color="accent" class="group-main-nav">
|
||||||
<app-organization-profile-01 [userSeq]="userSeq">
|
<a
|
||||||
|
mat-tab-link
|
||||||
|
(click)="activeLink = 0"
|
||||||
|
[active]="activeLink === 0 ? 'link' : undefined"
|
||||||
|
>{{ profileName }}</a
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
mat-tab-link
|
||||||
|
(click)="activeLink = 1"
|
||||||
|
[active]="activeLink === 1 ? 'link' : undefined"
|
||||||
|
>{{ tabName }}</a
|
||||||
|
>
|
||||||
|
</nav>
|
||||||
|
<div
|
||||||
|
class="profile-container"
|
||||||
|
[ngClass]="activeLink === 0 ? 'active' : ''"
|
||||||
|
fxFlex="44%"
|
||||||
|
>
|
||||||
|
<app-organization-profile-01
|
||||||
|
[userSeq]="userSeq"
|
||||||
|
(openChat)="onOpenCaht($event)"
|
||||||
|
(sendMessage)="onSendMessage($event)"
|
||||||
|
(sendCall)="onSendCall($event)"
|
||||||
|
(sendSms)="onSendSms($event)"
|
||||||
|
(createConference)="onCreateConference($event)"
|
||||||
|
(toggleFavorit)="onToggleFavorit($event)"
|
||||||
|
(toggleBuddy)="onToggleBuddy($event)"
|
||||||
|
(uploadProfileImage)="onUploadProfileImage($event)"
|
||||||
|
(updateIntro)="onUpdateIntro($event)"
|
||||||
|
(updateNickname)="onUpdateNickname($event)"
|
||||||
|
>
|
||||||
</app-organization-profile-01>
|
</app-organization-profile-01>
|
||||||
</div>
|
</div>
|
||||||
<div class="group-info-container" fxFlex="1 1 auto">
|
<div
|
||||||
|
class="group-info-container"
|
||||||
|
[ngClass]="activeLink === 1 ? 'active' : ''"
|
||||||
|
fxFlex="1 1 auto"
|
||||||
|
>
|
||||||
<app-sections-group-info [userSeq]="userSeq"></app-sections-group-info>
|
<app-sections-group-info [userSeq]="userSeq"></app-sections-group-info>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,8 +2,18 @@
|
||||||
|
|
||||||
.index-container {
|
.index-container {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding: 0 30px 30px;
|
padding: 30px 30px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
@include screen(lg) {
|
||||||
|
padding: 0 20px 30px;
|
||||||
|
}
|
||||||
|
@include screen(mid) {
|
||||||
|
padding: 0 15px 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include screen(xs) {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.subtitle {
|
.subtitle {
|
||||||
|
@ -18,12 +28,91 @@
|
||||||
color: $gray-re4;
|
color: $gray-re4;
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile-container {
|
.content-container {
|
||||||
height: 100%;
|
@include screen(lg) {
|
||||||
overflow: auto;
|
display: flex;
|
||||||
}
|
flex-direction: column !important;
|
||||||
|
}
|
||||||
|
@include screen(mid) {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column !important;
|
||||||
|
}
|
||||||
|
.group-main-nav {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
@include screen(xs) {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
.group-main-nav {
|
||||||
|
display: block;
|
||||||
|
position: fixed;
|
||||||
|
height: 49px;
|
||||||
|
top: 40px;
|
||||||
|
left: 75px;
|
||||||
|
z-index: 10;
|
||||||
|
width: calc(100% - 90px);
|
||||||
|
a {
|
||||||
|
width: 50%;
|
||||||
|
text-decoration: none;
|
||||||
|
color: rgba(51, 51, 51, 0.6);
|
||||||
|
font-weight: 600;
|
||||||
|
&.mat-tab-label-active {
|
||||||
|
color: rgba(51, 51, 51, 1);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.profile-container {
|
||||||
|
height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
flex: 1 0 460px !important;
|
||||||
|
max-width: inherit !important;
|
||||||
|
border-radius: 2px;
|
||||||
|
@include screen(custom, min, 1540) {
|
||||||
|
flex: 1 0 44% !important;
|
||||||
|
}
|
||||||
|
@include screen(lg) {
|
||||||
|
flex: 1 0 auto !important;
|
||||||
|
max-width: 100% !important;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
@include screen(mid) {
|
||||||
|
flex: 1 0 auto !important;
|
||||||
|
max-width: 100% !important;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
@include screen(xs) {
|
||||||
|
display: none;
|
||||||
|
&.active {
|
||||||
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.group-info-container {
|
.group-info-container {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
flex: 5 1 auto !important;
|
||||||
|
@include screen(lg) {
|
||||||
|
flex: 1 0 auto !important;
|
||||||
|
max-width: 100% !important;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
@include screen(mid) {
|
||||||
|
flex: 1 0 auto !important;
|
||||||
|
max-width: 100% !important;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
@include screen(xs) {
|
||||||
|
display: none;
|
||||||
|
&.active {
|
||||||
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,40 +1,194 @@
|
||||||
import { Subscription } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
|
import { takeUntil } from 'rxjs/operators';
|
||||||
|
|
||||||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
import {
|
||||||
|
Component,
|
||||||
|
OnInit,
|
||||||
|
OnDestroy,
|
||||||
|
ChangeDetectorRef,
|
||||||
|
ChangeDetectionStrategy
|
||||||
|
} from '@angular/core';
|
||||||
import { Router, ActivatedRoute, Params } from '@angular/router';
|
import { Router, ActivatedRoute, Params } from '@angular/router';
|
||||||
|
|
||||||
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
|
|
||||||
|
import { Store, select } from '@ngrx/store';
|
||||||
|
|
||||||
|
import { FileUploadItem } from '@ucap/api';
|
||||||
|
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 { LogService } from '@ucap/ng-logger';
|
import { LogService } from '@ucap/ng-logger';
|
||||||
|
import { I18nService } from '@ucap/ng-i18n';
|
||||||
|
import { UserSelector } from '@ucap/ng-store-organization';
|
||||||
|
import {
|
||||||
|
LoginSelector,
|
||||||
|
ConfigurationSelector
|
||||||
|
} from '@ucap/ng-store-authentication';
|
||||||
|
|
||||||
|
import { UserInfoTypes } 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';
|
||||||
|
|
||||||
import { QueryParams } from '../types/params.type';
|
import { QueryParams } from '../types/params.type';
|
||||||
|
import { AppChatService } from '@app/services/app-chat.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-pages-group-index',
|
selector: 'app-pages-group-index',
|
||||||
templateUrl: './index.page.component.html',
|
templateUrl: './index.page.component.html',
|
||||||
styleUrls: ['./index.page.component.scss']
|
styleUrls: ['./index.page.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class IndexPageComponent implements OnInit, OnDestroy {
|
export class IndexPageComponent implements OnInit, OnDestroy {
|
||||||
private paramsSubscription: Subscription;
|
private ngOnDestroySubject: Subject<void> = new Subject();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private activatedRoute: ActivatedRoute,
|
private activatedRoute: ActivatedRoute,
|
||||||
|
private store: Store<any>,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private logService: LogService
|
private logService: LogService,
|
||||||
) {}
|
private dialog: MatDialog,
|
||||||
|
private i18nService: I18nService,
|
||||||
|
private appFileServie: AppFileService,
|
||||||
|
private appAuthenticationService: AppAuthenticationService,
|
||||||
|
private changeDetectorRef: ChangeDetectorRef,
|
||||||
|
private appChatService: AppChatService,
|
||||||
|
private appGroupService: AppGroupService
|
||||||
|
) {
|
||||||
|
this.profileName = this.i18nService.t('organization:profile.me');
|
||||||
|
this.tabName = this.i18nService.t('organization:profile.chatWithUs');
|
||||||
|
}
|
||||||
|
|
||||||
userSeq: string;
|
userSeq: string = undefined;
|
||||||
|
user: User;
|
||||||
|
loginRes: LoginResponse;
|
||||||
|
versionInfo2Res: VersionInfo2Response;
|
||||||
|
activeLink = 0;
|
||||||
|
tabName: string;
|
||||||
|
profileName: string;
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.paramsSubscription = this.activatedRoute.queryParams.subscribe(
|
this.activatedRoute.queryParams
|
||||||
(params: Params) => {
|
.pipe(takeUntil(this.ngOnDestroySubject))
|
||||||
|
.subscribe((params: Params) => {
|
||||||
const seqParam = params[QueryParams.ID];
|
const seqParam = params[QueryParams.ID];
|
||||||
this.userSeq = !!seqParam ? seqParam : undefined;
|
if (!!seqParam) {
|
||||||
}
|
this.userSeq = seqParam;
|
||||||
);
|
} else {
|
||||||
|
this.userSeq = '';
|
||||||
|
}
|
||||||
|
this._refreshProfile();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.store
|
||||||
|
.pipe(takeUntil(this.ngOnDestroySubject), select(UserSelector.user))
|
||||||
|
.subscribe((user) => {
|
||||||
|
this.user = user;
|
||||||
|
this._refreshProfile();
|
||||||
|
});
|
||||||
|
this.store
|
||||||
|
.pipe(takeUntil(this.ngOnDestroySubject), select(LoginSelector.loginRes))
|
||||||
|
.subscribe((loginRes) => {
|
||||||
|
this.loginRes = loginRes;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.store
|
||||||
|
.pipe(
|
||||||
|
takeUntil(this.ngOnDestroySubject),
|
||||||
|
select(ConfigurationSelector.versionInfo2Response)
|
||||||
|
)
|
||||||
|
.subscribe((versionInfo2Res) => {
|
||||||
|
this.versionInfo2Res = versionInfo2Res;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
if (!!this.paramsSubscription) {
|
if (!!this.ngOnDestroySubject) {
|
||||||
this.paramsSubscription.unsubscribe();
|
this.ngOnDestroySubject.next();
|
||||||
|
this.ngOnDestroySubject.complete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onOpenCaht(userInfo: UserInfoSS) {
|
||||||
|
this.appChatService.newOpenRoom(
|
||||||
|
[Number(userInfo.seq) as any],
|
||||||
|
false,
|
||||||
|
this.user
|
||||||
|
);
|
||||||
|
}
|
||||||
|
onSendMessage(userInfo: UserInfoSS) {}
|
||||||
|
onSendCall(call: string) {}
|
||||||
|
onSendSms(employeeNum: string) {}
|
||||||
|
onCreateConference(userSeq: number) {}
|
||||||
|
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) }
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((reson) => this.logService.error(reson));
|
||||||
|
}
|
||||||
|
onUploadProfileImage(profileImageFileUploadItem: FileUploadItem) {
|
||||||
|
const loginSession = this.appAuthenticationService.getLoginSession();
|
||||||
|
|
||||||
|
const profile = {
|
||||||
|
userSeq: String(this.user.info.seq),
|
||||||
|
deviceType: loginSession.deviceType,
|
||||||
|
token: this.loginRes.tokenString,
|
||||||
|
file: profileImageFileUploadItem.file,
|
||||||
|
fileUploadItem: profileImageFileUploadItem
|
||||||
|
} as FileProfileSaveRequest;
|
||||||
|
|
||||||
|
this.appFileServie.fileProfileSave(
|
||||||
|
profile,
|
||||||
|
this.versionInfo2Res.profileUploadUrl
|
||||||
|
);
|
||||||
|
}
|
||||||
|
onUpdateIntro(intro: string) {
|
||||||
|
this.appGroupService.updateIntro(intro, UserInfoUpdateType.Intro);
|
||||||
|
}
|
||||||
|
|
||||||
|
onUpdateNickname(params: { userInfo: UserInfoTypes; nickname: string }) {
|
||||||
|
this.appGroupService.updateNickname(
|
||||||
|
params.userInfo as UserInfoF,
|
||||||
|
params.nickname
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _refreshProfile() {
|
||||||
|
if (!this.user || undefined === this.userSeq) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ('' === this.userSeq) {
|
||||||
|
this.userSeq = String(this.user.info.seq);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (String(this.user.info.seq) === String(this.userSeq)) {
|
||||||
|
this.profileName = this.i18nService.t('organization:profile.me');
|
||||||
|
this.tabName = this.i18nService.t('organization:profile.unreadChat');
|
||||||
|
} else {
|
||||||
|
this.profileName = this.i18nService.t('organization:profile.other');
|
||||||
|
this.tabName = this.i18nService.t('organization:profile.chatWithUs');
|
||||||
|
}
|
||||||
|
this.changeDetectorRef.markForCheck();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<div class="sidenav-container" fxFlexFill fxLayout="column">
|
<div class="sidenav-container group" fxFlexFill fxLayout="column">
|
||||||
<div class="title-section" fxFlex="0 0 50px" fxLayout="row">
|
<div class="title-section" fxFlex="0 0 50px" fxLayout="row">
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<h3 fxFlex="1 1 auto">그룹</h3>
|
<h3 fxFlex="1 1 auto">{{ 'group:label.group' | ucapI18n }}</h3>
|
||||||
<div class="menu-btn" fxFlex="80px">
|
<div class="menu-btn">
|
||||||
<button
|
<button
|
||||||
mat-icon-button
|
mat-icon-button
|
||||||
[matMenuTriggerFor]="groupViewMenu"
|
[matMenuTriggerFor]="groupViewMenu"
|
||||||
|
@ -21,43 +21,58 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="extra-box" fxFlex="0 0 50px">
|
<div class="extra-box" fxFlex="0 0 50px">
|
||||||
<app-organization-search-for-tenant [(searchData)]="companySearchData">
|
<app-organization-search-for-tenant
|
||||||
|
[(searchData)]="companySearchData"
|
||||||
|
(canceled)="onSearchCancel()"
|
||||||
|
>
|
||||||
</app-organization-search-for-tenant>
|
</app-organization-search-for-tenant>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="1 1 auto">
|
<div fxFlex="1 1 auto">
|
||||||
<app-sections-group-list
|
<app-sections-group-list
|
||||||
#sectionGroupList
|
#sectionGroupList
|
||||||
fxFlexFill
|
|
||||||
[searchData]="companySearchData"
|
[searchData]="companySearchData"
|
||||||
[showType]="showType"
|
[showType]="showType"
|
||||||
|
(clickUser)="onClickUser($event)"
|
||||||
></app-sections-group-list>
|
></app-sections-group-list>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<mat-menu #groupMenu="matMenu">
|
<mat-menu #groupMenu="matMenu">
|
||||||
<button mat-menu-item (click)="onClickGroupMenu('GROUP_NEW')">
|
<button mat-menu-item (click)="onClickGroupMenu('GROUP_NEW')">
|
||||||
{{ 'moreMenu.group.addNew' | ucapI18n }}
|
<mat-icon matPrefix class="material-icons-outlined">person_add</mat-icon
|
||||||
|
>{{ 'group:contextMenu.addNewGroup' | ucapI18n }}
|
||||||
</button>
|
</button>
|
||||||
<button mat-menu-item (click)="onClickGroupMenu('GROUP_EXPAND_MORE')">
|
<button mat-menu-item (click)="onClickGroupMenu('GROUP_EXPAND_MORE')">
|
||||||
{{ 'moreMenu.group.expandMore' | ucapI18n }}
|
<mat-icon matPrefix>keyboard_arrow_down</mat-icon
|
||||||
|
>{{ 'group:contextMenu.expandMore' | ucapI18n }}
|
||||||
</button>
|
</button>
|
||||||
<button mat-menu-item (click)="onClickGroupMenu('GROUP_EXPAND_LESS')">
|
<button mat-menu-item (click)="onClickGroupMenu('GROUP_EXPAND_LESS')">
|
||||||
{{ 'moreMenu.group.expandLess' | ucapI18n }}
|
<mat-icon matPrefix>keyboard_arrow_up</mat-icon
|
||||||
</button>
|
>{{ 'group:contextMenu.expandLess' | ucapI18n }}
|
||||||
<button mat-menu-item (click)="onClickGroupMenu('GROUP_CHANGE_ODER')">
|
|
||||||
{{ 'moreMenu.group.changeOrder' | ucapI18n }}
|
|
||||||
</button>
|
</button>
|
||||||
|
<!-- <button mat-menu-item (click)="onClickGroupMenu('GROUP_CHANGE_ODER')">
|
||||||
|
<mat-icon matPrefix>low_priority</mat-icon
|
||||||
|
>{{ 'group:contextMenu.changeOrder' | ucapI18n }}
|
||||||
|
</button> -->
|
||||||
</mat-menu>
|
</mat-menu>
|
||||||
|
|
||||||
<mat-menu #groupViewMenu="matMenu">
|
<mat-menu #groupViewMenu="matMenu">
|
||||||
<button mat-menu-item (click)="onClickShowGroupMenu('ALL')">
|
<button mat-menu-item (click)="onClickShowGroupMenu(sortViewType.all)">
|
||||||
{{ 'moreMenu.show.all' | ucapI18n }}
|
<mat-icon matPrefix>{{ showGroupMenuIcon(sortViewType.all) }}</mat-icon
|
||||||
|
>{{ 'group:contextMenu.all' | ucapI18n }}
|
||||||
</button>
|
</button>
|
||||||
<button mat-menu-item (click)="onClickShowGroupMenu('ONLINE_BUDDY')">
|
<button
|
||||||
{{ 'moreMenu.show.onlineBuddy' | ucapI18n }}
|
mat-menu-item
|
||||||
|
(click)="onClickShowGroupMenu(sortViewType.onlineBuddy)"
|
||||||
|
>
|
||||||
|
<mat-icon matPrefix>{{
|
||||||
|
showGroupMenuIcon(sortViewType.onlineBuddy)
|
||||||
|
}}</mat-icon
|
||||||
|
>{{ 'group:contextMenu.onlineBuddy' | ucapI18n }}
|
||||||
</button>
|
</button>
|
||||||
<button mat-menu-item (click)="onClickShowGroupMenu('ON_OFF')">
|
<button mat-menu-item (click)="onClickShowGroupMenu(sortViewType.onOff)">
|
||||||
{{ 'moreMenu.show.onOff' | ucapI18n }}
|
<mat-icon matPrefix>{{ showGroupMenuIcon(sortViewType.onOff) }}</mat-icon
|
||||||
|
>{{ 'group:contextMenu.onOffBuddy' | ucapI18n }}
|
||||||
</button>
|
</button>
|
||||||
</mat-menu>
|
</mat-menu>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
@import '~@ucap/lg-scss/mixins';
|
@import '~@ucap/lg-scss/mixins';
|
||||||
|
|
||||||
.sidenav-container {
|
.sidenav-container.group {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: column;
|
flex-flow: column;
|
||||||
|
@ -24,9 +24,6 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
.menu-btn {
|
|
||||||
justify-self: end;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,39 +1,46 @@
|
||||||
import { of, Subject } from 'rxjs';
|
import { of, Subject } from 'rxjs';
|
||||||
import { take, map, catchError, takeUntil } from 'rxjs/operators';
|
import { take, map, catchError } from 'rxjs/operators';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Component,
|
Component,
|
||||||
OnInit,
|
OnInit,
|
||||||
OnDestroy,
|
OnDestroy,
|
||||||
ChangeDetectorRef,
|
ChangeDetectorRef,
|
||||||
ViewChild
|
ViewChild,
|
||||||
|
ChangeDetectionStrategy
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { ActivatedRoute, Router, Params } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
|
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
|
|
||||||
import { ParamsUtil } from '@ucap/ng-core';
|
|
||||||
import { LogService } from '@ucap/ng-logger';
|
import { LogService } from '@ucap/ng-logger';
|
||||||
import { I18nService } from '@ucap/ng-i18n';
|
import { I18nService } from '@ucap/ng-i18n';
|
||||||
|
|
||||||
|
import { SearchData } from '@app/ucap/organization/models/search-data';
|
||||||
|
|
||||||
import { CreateDialogComponent } from '@app/sections/group/dialogs/create.dialog.component';
|
import { CreateDialogComponent } from '@app/sections/group/dialogs/create.dialog.component';
|
||||||
import { ListSectionComponent } from '@app/sections/group/components/list.section.component';
|
import { ListSectionComponent } from '@app/sections/group/components/list.section.component';
|
||||||
import { SearchData } from '@app/ucap/organization/models/search-data';
|
import { UserInfo } from '@ucap/protocol-sync';
|
||||||
import { QueryParams } from '@app/pages/organization/types/params.type';
|
import { SortViewType } from '../types/sort-view.type';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-pages-group-sidenav',
|
selector: 'app-pages-group-sidenav',
|
||||||
templateUrl: './sidenav.page.component.html',
|
templateUrl: './sidenav.page.component.html',
|
||||||
styleUrls: ['./sidenav.page.component.scss']
|
styleUrls: ['./sidenav.page.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class SidenavPageComponent implements OnInit, OnDestroy {
|
export class SidenavPageComponent implements OnInit, OnDestroy {
|
||||||
@ViewChild('sectionGroupList', { static: false })
|
@ViewChild('sectionGroupList', { static: false })
|
||||||
sectionGroupList: ListSectionComponent;
|
sectionGroupList: ListSectionComponent;
|
||||||
|
|
||||||
set companySearchData(searchData: SearchData) {
|
set companySearchData(searchData: SearchData) {
|
||||||
this._companySearchData = searchData;
|
if (!!searchData && searchData.searchWord !== '') {
|
||||||
|
this._companySearchData = { ...searchData, bySearch: true };
|
||||||
|
} else {
|
||||||
|
this._companySearchData = { ...searchData, bySearch: false };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
get companySearchData() {
|
get companySearchData() {
|
||||||
return this._companySearchData;
|
return this._companySearchData;
|
||||||
|
@ -41,9 +48,10 @@ export class SidenavPageComponent implements OnInit, OnDestroy {
|
||||||
// tslint:disable-next-line: variable-name
|
// tslint:disable-next-line: variable-name
|
||||||
_companySearchData: SearchData;
|
_companySearchData: SearchData;
|
||||||
|
|
||||||
showType: string;
|
showType: SortViewType;
|
||||||
|
sortViewType = SortViewType;
|
||||||
|
|
||||||
private ngOnDestroySubject: Subject<boolean>;
|
private ngOnDestroySubject: Subject<void> = new Subject();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private activatedRoute: ActivatedRoute,
|
private activatedRoute: ActivatedRoute,
|
||||||
|
@ -53,17 +61,19 @@ export class SidenavPageComponent implements OnInit, OnDestroy {
|
||||||
private store: Store<any>,
|
private store: Store<any>,
|
||||||
private changeDetectorRef: ChangeDetectorRef,
|
private changeDetectorRef: ChangeDetectorRef,
|
||||||
public dialog: MatDialog
|
public dialog: MatDialog
|
||||||
) {
|
) {}
|
||||||
this.i18nService.setDefaultNamespace('group');
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.ngOnDestroySubject = new Subject<boolean>();
|
this.showType = SortViewType.all;
|
||||||
|
this.showGroupMenuIcon(SortViewType.all);
|
||||||
this.showType = 'ALL';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {}
|
ngOnDestroy(): void {
|
||||||
|
if (!!this.ngOnDestroySubject) {
|
||||||
|
this.ngOnDestroySubject.next();
|
||||||
|
this.ngOnDestroySubject.complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onClickFab(event: MouseEvent) {}
|
onClickFab(event: MouseEvent) {}
|
||||||
|
|
||||||
|
@ -72,8 +82,7 @@ export class SidenavPageComponent implements OnInit, OnDestroy {
|
||||||
case 'GROUP_NEW':
|
case 'GROUP_NEW':
|
||||||
{
|
{
|
||||||
const dialogRef = this.dialog.open(CreateDialogComponent, {
|
const dialogRef = this.dialog.open(CreateDialogComponent, {
|
||||||
width: '100%',
|
panelClass: 'max-create-dialog'
|
||||||
height: '100%'
|
|
||||||
});
|
});
|
||||||
|
|
||||||
dialogRef
|
dialogRef
|
||||||
|
@ -105,23 +114,48 @@ export class SidenavPageComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onClickShowGroupMenu(menuType: string) {
|
onClickShowGroupMenu(menuType: SortViewType) {
|
||||||
switch (menuType) {
|
switch (menuType) {
|
||||||
case 'ALL':
|
case SortViewType.all:
|
||||||
{
|
{
|
||||||
this.showType = 'ALL';
|
this.showType = SortViewType.all;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'ONLINE_BUDDY':
|
case SortViewType.onlineBuddy:
|
||||||
{
|
{
|
||||||
this.showType = 'ONLINE_BUDDY';
|
this.showType = SortViewType.onlineBuddy;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'ON_OFF':
|
case SortViewType.onOff:
|
||||||
{
|
{
|
||||||
this.showType = 'ON_OFF';
|
this.showType = SortViewType.onOff;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
onSearchCancel() {
|
||||||
|
this.companySearchData = { ...this.companySearchData, searchWord: '' };
|
||||||
|
}
|
||||||
|
|
||||||
|
showGroupMenuIcon(menuType: SortViewType): string {
|
||||||
|
if (this.showType === menuType) {
|
||||||
|
return 'check_circle';
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'check_circle_outline';
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickUser(userInfo: UserInfo) {
|
||||||
|
this.router.navigate(
|
||||||
|
[
|
||||||
|
'group',
|
||||||
|
{
|
||||||
|
outlets: { content: 'index' }
|
||||||
|
}
|
||||||
|
],
|
||||||
|
{
|
||||||
|
queryParams: { id: Number(userInfo.seq) }
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { FlexLayoutModule } from '@angular/flex-layout';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatMenuModule } from '@angular/material/menu';
|
import { MatMenuModule } from '@angular/material/menu';
|
||||||
|
import { MatTabsModule } from '@angular/material/tabs';
|
||||||
|
|
||||||
import { UiModule } from '@ucap/ng-ui';
|
import { UiModule } from '@ucap/ng-ui';
|
||||||
|
|
||||||
|
@ -26,6 +27,7 @@ import { I18nModule, UCAP_I18N_NAMESPACE } from '@ucap/ng-i18n';
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
MatIconModule,
|
MatIconModule,
|
||||||
MatMenuModule,
|
MatMenuModule,
|
||||||
|
MatTabsModule,
|
||||||
|
|
||||||
AppOrganizationModule,
|
AppOrganizationModule,
|
||||||
|
|
||||||
|
|
5
src/app/pages/group/types/sort-view.type.ts
Normal file
5
src/app/pages/group/types/sort-view.type.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
export enum SortViewType {
|
||||||
|
all = 'ALL',
|
||||||
|
onlineBuddy = 'ONLINE_BUDDY',
|
||||||
|
onOff = 'ON_OFF'
|
||||||
|
}
|
|
@ -1 +1,8 @@
|
||||||
Index page of message is works!
|
<!--Index page of message is works!-->
|
||||||
|
<div class="index-page-empty">
|
||||||
|
<div class="ico-coming-soon"></div>
|
||||||
|
<div class="coming-soon-index-copy">
|
||||||
|
<span>Coming Soon</span>
|
||||||
|
<span class="guide-text">곧 새로운 모습으로 찾아 뵙겠습니다.</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
.index-page-empty {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
.ico-coming-soon {
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
margin-top: -100px;
|
||||||
|
background-image: url(../../../../assets/images/ico/img_coming_soon.png);
|
||||||
|
background-size: 100% auto;
|
||||||
|
}
|
||||||
|
.coming-soon-index-copy {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 2.4em;
|
||||||
|
color: #666;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 0 20px;
|
||||||
|
//border-top: 1px solid #ccc;
|
||||||
|
//border-bottom: 1px solid #ccc;
|
||||||
|
span {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.guide-text {
|
||||||
|
padding-top: 10px;
|
||||||
|
font-size: 0.54em;
|
||||||
|
color: #999;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,10 @@
|
||||||
<div class="index-page-container" fxLayout="column">
|
<div class="index-page-container" fxLayout="column">
|
||||||
<!-- search start-->
|
<!-- search start-->
|
||||||
<div fxFlex="0 0 50px">
|
<div fxFlex="0 0 50px">
|
||||||
<app-organization-search-for-tenant [(searchData)]="companySearchData">
|
<app-organization-search-for-tenant
|
||||||
|
[(searchData)]="companySearchData"
|
||||||
|
(canceled)="onCanceledSearch()"
|
||||||
|
>
|
||||||
</app-organization-search-for-tenant>
|
</app-organization-search-for-tenant>
|
||||||
</div>
|
</div>
|
||||||
<!-- search end-->
|
<!-- search end-->
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
.index-page-container {
|
.index-page-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,28 @@
|
||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
import { takeUntil } from 'rxjs/operators';
|
import { takeUntil } from 'rxjs/operators';
|
||||||
|
|
||||||
import { Component, OnInit, OnDestroy, ChangeDetectorRef } from '@angular/core';
|
import {
|
||||||
|
Component,
|
||||||
|
OnInit,
|
||||||
|
OnDestroy,
|
||||||
|
ChangeDetectorRef,
|
||||||
|
ChangeDetectionStrategy
|
||||||
|
} from '@angular/core';
|
||||||
import { ActivatedRoute, Router, Params } from '@angular/router';
|
import { ActivatedRoute, Router, Params } from '@angular/router';
|
||||||
|
|
||||||
import { Store } from '@ngrx/store';
|
|
||||||
|
|
||||||
import { ParamsUtil } from '@ucap/ng-core';
|
import { ParamsUtil } from '@ucap/ng-core';
|
||||||
|
|
||||||
|
import { AppAuthenticationService } from '@app/services/app-authentication.service';
|
||||||
import { SearchData } from '@app/ucap/organization/models/search-data';
|
import { SearchData } from '@app/ucap/organization/models/search-data';
|
||||||
|
|
||||||
import { QueryParams } from '../types/params.type';
|
import { QueryParams } from '../types/params.type';
|
||||||
|
import { UserStore } from '@app/models/user-store';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-pages-organization-index',
|
selector: 'app-pages-organization-index',
|
||||||
templateUrl: './index.page.component.html',
|
templateUrl: './index.page.component.html',
|
||||||
styleUrls: ['./index.page.component.scss']
|
styleUrls: ['./index.page.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class IndexPageComponent implements OnInit, OnDestroy {
|
export class IndexPageComponent implements OnInit, OnDestroy {
|
||||||
set companySearchData(searchData: SearchData) {
|
set companySearchData(searchData: SearchData) {
|
||||||
|
@ -32,18 +39,19 @@ export class IndexPageComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
deptSeq: string;
|
deptSeq: string;
|
||||||
|
|
||||||
private ngOnDestroySubject: Subject<boolean>;
|
private ngOnDestroySubject: Subject<void> = new Subject();
|
||||||
|
private userStore: UserStore;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private store: Store<any>,
|
private appAuthenticationService: AppAuthenticationService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private activatedRoute: ActivatedRoute,
|
private activatedRoute: ActivatedRoute,
|
||||||
private changeDetectorRef: ChangeDetectorRef
|
private changeDetectorRef: ChangeDetectorRef
|
||||||
) {}
|
) {
|
||||||
|
this.userStore = this.appAuthenticationService.getUserStore();
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.ngOnDestroySubject = new Subject<boolean>();
|
|
||||||
|
|
||||||
this.activatedRoute.queryParams
|
this.activatedRoute.queryParams
|
||||||
.pipe(takeUntil(this.ngOnDestroySubject))
|
.pipe(takeUntil(this.ngOnDestroySubject))
|
||||||
.subscribe((params) => {
|
.subscribe((params) => {
|
||||||
|
@ -57,22 +65,31 @@ export class IndexPageComponent implements OnInit, OnDestroy {
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!!deptSeq && this.deptSeq !== deptSeq) {
|
||||||
|
this.deptSeq = deptSeq;
|
||||||
|
}
|
||||||
|
|
||||||
this.deptSearchData = {
|
this.deptSearchData = {
|
||||||
deptSeq: bySearch ? undefined : deptSeq,
|
deptSeq: bySearch ? undefined : deptSeq,
|
||||||
companyCode: bySearch ? companyCode : undefined,
|
companyCode: !!companyCode
|
||||||
searchWord: bySearch ? searchWord : undefined,
|
? companyCode
|
||||||
|
: this.userStore.companyCode,
|
||||||
|
searchWord: bySearch ? decodeURIComponent(searchWord) : undefined,
|
||||||
bySearch
|
bySearch
|
||||||
};
|
};
|
||||||
|
|
||||||
this._companySearchData = {
|
this._companySearchData = {
|
||||||
...this.deptSearchData
|
...this.deptSearchData
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.changeDetectorRef.markForCheck();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
if (!!this.ngOnDestroySubject) {
|
if (!!this.ngOnDestroySubject) {
|
||||||
|
this.ngOnDestroySubject.next();
|
||||||
this.ngOnDestroySubject.complete();
|
this.ngOnDestroySubject.complete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,9 +97,21 @@ export class IndexPageComponent implements OnInit, OnDestroy {
|
||||||
onChangedCompanySearch() {
|
onChangedCompanySearch() {
|
||||||
const queryParams: Params = {};
|
const queryParams: Params = {};
|
||||||
queryParams[QueryParams.COMPANY_CODE] = this._companySearchData.companyCode;
|
queryParams[QueryParams.COMPANY_CODE] = this._companySearchData.companyCode;
|
||||||
queryParams[QueryParams.SEARCH_WORD] = this._companySearchData.searchWord;
|
queryParams[QueryParams.SEARCH_WORD] = encodeURIComponent(
|
||||||
|
this._companySearchData.searchWord
|
||||||
|
);
|
||||||
queryParams[QueryParams.BY_SEARCH] = String(true);
|
queryParams[QueryParams.BY_SEARCH] = String(true);
|
||||||
|
|
||||||
|
this._navigate(queryParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
onCanceledSearch() {
|
||||||
|
const queryParams: Params = {};
|
||||||
|
queryParams[QueryParams.DEPT_SEQ] = String(this.deptSeq);
|
||||||
|
this._navigate(queryParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _navigate(queryParams: Params = {}) {
|
||||||
this.router.navigate(
|
this.router.navigate(
|
||||||
[
|
[
|
||||||
'organization',
|
'organization',
|
||||||
|
|
|
@ -1,22 +1,12 @@
|
||||||
<div class="sidenav-container" fxFlexFill fxLayout="column">
|
<div class="sidenav-container" fxFlexFill fxLayout="column">
|
||||||
<div class="sub-header" fxFlex="50px" fxLayout="row">
|
<div class="sub-header" fxFlex="50px" fxLayout="row">
|
||||||
<div fxFlex="1 1 auto">
|
<div fxFlex="1 1 auto">
|
||||||
<h3>조직도</h3>
|
<h3>{{ 'organization:label.organization' | ucapI18n }}</h3>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="menu-btn" fxFlex="0 0 40px">
|
|
||||||
<button
|
|
||||||
mat-icon-button
|
|
||||||
[matMenuTriggerFor]="organizationMenu"
|
|
||||||
aria-label="organization menu"
|
|
||||||
>
|
|
||||||
<mat-icon>more_vert</mat-icon>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div *ngIf="!!displayRootDept" class="extra-box" fxFlex="0 0 50px">
|
||||||
<div class="extra-box" fxFlex="0 0 50px">
|
<mat-icon matPrefix class="ico-business">business</mat-icon
|
||||||
<mat-icon matPrefix class="ico-business">business</mat-icon>LG CNS
|
>{{ displayRootDept | ucapOrganizationTranslate: 'name' }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="1 1 auto">
|
<div fxFlex="1 1 auto">
|
||||||
|
@ -26,8 +16,3 @@
|
||||||
></app-organization-tree>
|
></app-organization-tree>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<mat-menu #organizationMenu="matMenu">
|
|
||||||
<button mat-menu-item>Item 1</button>
|
|
||||||
<button mat-menu-item>Item 2</button>
|
|
||||||
</mat-menu>
|
|
||||||
|
|
|
@ -1,27 +1,44 @@
|
||||||
import { Subject } from 'rxjs';
|
import { Subject, combineLatest } from 'rxjs';
|
||||||
import { takeUntil } from 'rxjs/operators';
|
import { takeUntil } from 'rxjs/operators';
|
||||||
|
|
||||||
import { Component, OnInit, OnDestroy, ChangeDetectorRef } from '@angular/core';
|
import {
|
||||||
|
Component,
|
||||||
|
OnInit,
|
||||||
|
OnDestroy,
|
||||||
|
ChangeDetectorRef,
|
||||||
|
ChangeDetectionStrategy
|
||||||
|
} from '@angular/core';
|
||||||
import { Router, ActivatedRoute, Params } from '@angular/router';
|
import { Router, ActivatedRoute, Params } from '@angular/router';
|
||||||
|
|
||||||
|
import { Store, select } from '@ngrx/store';
|
||||||
|
|
||||||
import { LogService } from '@ucap/ng-logger';
|
import { LogService } from '@ucap/ng-logger';
|
||||||
import { DeptInfo } from '@ucap/protocol-query';
|
import { DeptInfo } from '@ucap/protocol-query';
|
||||||
|
|
||||||
|
import { DepartmentSelector, UserSelector } from '@ucap/ng-store-organization';
|
||||||
|
import { LoginSelector } from '@ucap/ng-store-authentication';
|
||||||
|
|
||||||
|
import { environment } from '@environments';
|
||||||
|
|
||||||
import { QueryParams } from '../types/params.type';
|
import { QueryParams } from '../types/params.type';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-pages-ogranization-sidenav',
|
selector: 'app-pages-ogranization-sidenav',
|
||||||
templateUrl: './sidenav.page.component.html',
|
templateUrl: './sidenav.page.component.html',
|
||||||
styleUrls: ['./sidenav.page.component.scss']
|
styleUrls: ['./sidenav.page.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class SidenavPageComponent implements OnInit, OnDestroy {
|
export class SidenavPageComponent implements OnInit, OnDestroy {
|
||||||
initialExpanded: number;
|
initialExpanded: number;
|
||||||
|
displayRoot = false;
|
||||||
|
displayRootDept: DeptInfo;
|
||||||
|
|
||||||
private ngOnDestroySubject: Subject<void>;
|
private ngOnDestroySubject: Subject<void> = new Subject();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private activatedRoute: ActivatedRoute,
|
private activatedRoute: ActivatedRoute,
|
||||||
|
private store: Store<any>,
|
||||||
private changeDetectorRef: ChangeDetectorRef,
|
private changeDetectorRef: ChangeDetectorRef,
|
||||||
private logService: LogService
|
private logService: LogService
|
||||||
) {
|
) {
|
||||||
|
@ -29,22 +46,56 @@ export class SidenavPageComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.ngOnDestroySubject = new Subject<void>();
|
// this.activatedRoute.queryParams
|
||||||
|
// .pipe(takeUntil(this.ngOnDestroySubject))
|
||||||
|
// .subscribe((params) => {
|
||||||
|
// if (!!params) {
|
||||||
|
// const deptSeq = params[QueryParams.DEPT_SEQ];
|
||||||
|
// if (!!deptSeq) {
|
||||||
|
// this.initialExpanded = Number(deptSeq);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
this.activatedRoute.queryParams
|
combineLatest([
|
||||||
|
this.activatedRoute.queryParams,
|
||||||
|
this.store.pipe(select(UserSelector.user))
|
||||||
|
])
|
||||||
.pipe(takeUntil(this.ngOnDestroySubject))
|
.pipe(takeUntil(this.ngOnDestroySubject))
|
||||||
.subscribe((params) => {
|
.subscribe(([params, user]) => {
|
||||||
|
let existParams = false;
|
||||||
if (!!params) {
|
if (!!params) {
|
||||||
const deptSeq = params[QueryParams.DEPT_SEQ];
|
const deptSeq = params[QueryParams.DEPT_SEQ];
|
||||||
if (!!deptSeq) {
|
if (!!deptSeq) {
|
||||||
|
existParams = true;
|
||||||
this.initialExpanded = Number(deptSeq);
|
this.initialExpanded = Number(deptSeq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!existParams) {
|
||||||
|
this.initialExpanded = user.departmentCode;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.store
|
||||||
|
.pipe(
|
||||||
|
takeUntil(this.ngOnDestroySubject),
|
||||||
|
select(DepartmentSelector.departmentInfoList)
|
||||||
|
)
|
||||||
|
.subscribe((deptInfoList) => {
|
||||||
|
if (!environment.productConfig.organization.displayRoot) {
|
||||||
|
if (!!deptInfoList && deptInfoList.length > 0) {
|
||||||
|
this.displayRootDept = deptInfoList.find(
|
||||||
|
(item) => item.type === 'R'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
if (!!this.ngOnDestroySubject) {
|
if (!!this.ngOnDestroySubject) {
|
||||||
|
this.ngOnDestroySubject.next();
|
||||||
this.ngOnDestroySubject.complete();
|
this.ngOnDestroySubject.complete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,7 +103,6 @@ export class SidenavPageComponent implements OnInit, OnDestroy {
|
||||||
onClickedTree(node: DeptInfo) {
|
onClickedTree(node: DeptInfo) {
|
||||||
const queryParams: Params = {};
|
const queryParams: Params = {};
|
||||||
queryParams[QueryParams.DEPT_SEQ] = String(node.seq);
|
queryParams[QueryParams.DEPT_SEQ] = String(node.seq);
|
||||||
queryParams[QueryParams.BY_SEARCH] = String(false);
|
|
||||||
|
|
||||||
this.router.navigate(
|
this.router.navigate(
|
||||||
[
|
[
|
||||||
|
|
|
@ -12,6 +12,9 @@ import { AppOrganizationSectionModule } from '@app/sections/organization/organiz
|
||||||
import { AppOrganizationRoutingPageModule } from './organization-routing.page.module';
|
import { AppOrganizationRoutingPageModule } from './organization-routing.page.module';
|
||||||
|
|
||||||
import { COMPONENTS } from './components';
|
import { COMPONENTS } from './components';
|
||||||
|
import { I18nModule, UCAP_I18N_NAMESPACE } from '@ucap/ng-i18n';
|
||||||
|
import { UiModule } from '@ucap/ng-ui';
|
||||||
|
import { OrganizationUiModule } from '@ucap/ng-ui-organization';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -24,9 +27,19 @@ import { COMPONENTS } from './components';
|
||||||
|
|
||||||
AppOrganizationModule,
|
AppOrganizationModule,
|
||||||
AppOrganizationSectionModule,
|
AppOrganizationSectionModule,
|
||||||
AppOrganizationRoutingPageModule
|
AppOrganizationRoutingPageModule,
|
||||||
|
|
||||||
|
I18nModule,
|
||||||
|
OrganizationUiModule,
|
||||||
|
UiModule
|
||||||
],
|
],
|
||||||
declarations: [...COMPONENTS],
|
declarations: [...COMPONENTS],
|
||||||
entryComponents: []
|
entryComponents: [],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: UCAP_I18N_NAMESPACE,
|
||||||
|
useValue: ['organization', 'common']
|
||||||
|
}
|
||||||
|
]
|
||||||
})
|
})
|
||||||
export class AppOrganizationPageModule {}
|
export class AppOrganizationPageModule {}
|
||||||
|
|
|
@ -4,67 +4,49 @@ import { ReactiveFormsModule } from '@angular/forms';
|
||||||
|
|
||||||
import { FlexLayoutModule } from '@angular/flex-layout';
|
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||||
|
|
||||||
import { I18nModule, UCAP_I18N_NAMESPACE } from '@ucap/ng-i18n';
|
|
||||||
import { AuthenticationUiModule } from '@ucap/ng-ui-authentication';
|
|
||||||
|
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatButtonToggleModule } from '@angular/material/button-toggle';
|
|
||||||
import { MatCardModule } from '@angular/material/card';
|
|
||||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||||
import { MatDatepickerModule } from '@angular/material/datepicker';
|
|
||||||
import { MatDialogModule } from '@angular/material/dialog';
|
|
||||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatMenuModule } from '@angular/material/menu';
|
import { MatRadioModule } from '@angular/material/radio';
|
||||||
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
|
||||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
|
||||||
import { MatSelectModule } from '@angular/material/select';
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
import { MatSidenavModule } from '@angular/material/sidenav';
|
|
||||||
import { MatSliderModule } from '@angular/material/slider';
|
|
||||||
import { MatTabsModule } from '@angular/material/tabs';
|
import { MatTabsModule } from '@angular/material/tabs';
|
||||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
||||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
import { I18nModule } from '@ucap/ng-i18n';
|
||||||
|
import { UiModule } from '@ucap/ng-ui';
|
||||||
|
import { AuthenticationUiModule } from '@ucap/ng-ui-authentication';
|
||||||
|
import { OrganizationUiModule } from '@ucap/ng-ui-organization';
|
||||||
|
|
||||||
|
import { AppLayoutsModule } from '@app/layouts/layouts.module';
|
||||||
|
import { AppOrganizationModule } from '@app/ucap/organization/organization.module';
|
||||||
|
|
||||||
import { COMPONENTS } from './components';
|
import { COMPONENTS } from './components';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
FlexLayoutModule,
|
|
||||||
MatCheckboxModule,
|
|
||||||
I18nModule,
|
|
||||||
AuthenticationUiModule,
|
|
||||||
|
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
|
FlexLayoutModule,
|
||||||
|
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
MatButtonToggleModule,
|
MatCheckboxModule,
|
||||||
MatCardModule,
|
|
||||||
MatDatepickerModule,
|
|
||||||
MatDialogModule,
|
|
||||||
MatIconModule,
|
MatIconModule,
|
||||||
MatInputModule,
|
MatInputModule,
|
||||||
MatMenuModule,
|
MatRadioModule,
|
||||||
MatProgressBarModule,
|
|
||||||
MatProgressSpinnerModule,
|
|
||||||
MatCheckboxModule,
|
|
||||||
MatSelectModule,
|
MatSelectModule,
|
||||||
MatSidenavModule,
|
|
||||||
MatSliderModule,
|
|
||||||
MatTabsModule,
|
MatTabsModule,
|
||||||
MatTooltipModule,
|
|
||||||
MatToolbarModule,
|
I18nModule,
|
||||||
MatFormFieldModule,
|
|
||||||
MatSelectModule
|
UiModule,
|
||||||
|
AuthenticationUiModule,
|
||||||
|
OrganizationUiModule,
|
||||||
|
|
||||||
|
AppLayoutsModule,
|
||||||
|
AppOrganizationModule
|
||||||
],
|
],
|
||||||
exports: [...COMPONENTS],
|
exports: [...COMPONENTS],
|
||||||
declarations: [...COMPONENTS],
|
declarations: [...COMPONENTS],
|
||||||
entryComponents: [],
|
entryComponents: []
|
||||||
providers: [
|
|
||||||
{
|
|
||||||
provide: UCAP_I18N_NAMESPACE,
|
|
||||||
useValue: ['authentication']
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
export class AppAccountSectionModule {}
|
export class AppAccountSectionModule {}
|
||||||
|
|
|
@ -1,127 +0,0 @@
|
||||||
<div class="login-box">
|
|
||||||
<ng-content select="[ucapAuthenticationLogin='header']"></ng-content>
|
|
||||||
|
|
||||||
<div class="login-content">
|
|
||||||
<form name="loginForm" [formGroup]="loginForm" novalidate>
|
|
||||||
<mat-form-field
|
|
||||||
[style.display]="!!fixedCompanyCode ? 'none' : 'block'"
|
|
||||||
class="login-company"
|
|
||||||
appearance="none"
|
|
||||||
>
|
|
||||||
<mat-select
|
|
||||||
[formControl]="companyCodeFormControl"
|
|
||||||
[value]="companyCode || fixedCompanyCode"
|
|
||||||
placeholder="{{ 'login.labels.selectCompany' | ucapI18n }}"
|
|
||||||
class="login-input-area login-select-form"
|
|
||||||
>
|
|
||||||
<mat-option
|
|
||||||
*ngFor="let company of companyList"
|
|
||||||
[value]="company.companyCode"
|
|
||||||
>{{ company.companyName }}
|
|
||||||
</mat-option>
|
|
||||||
</mat-select>
|
|
||||||
</mat-form-field>
|
|
||||||
|
|
||||||
<div class="login-input-area idpass-type">
|
|
||||||
<mat-form-field
|
|
||||||
class="login-idpass-txt"
|
|
||||||
appearance="none"
|
|
||||||
floatLabel=""
|
|
||||||
>
|
|
||||||
<!-- <mat-label>{{ 'login.fields.loginId' | ucapI18n }}</mat-label> -->
|
|
||||||
<input
|
|
||||||
matInput
|
|
||||||
[formControl]="loginIdFormControl"
|
|
||||||
placeholder="{{ 'login.fields.loginId' | ucapI18n }}"
|
|
||||||
/>
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="login-input-area idpass-type pass-type">
|
|
||||||
<mat-form-field class="login-idpass-txt" appearance="none">
|
|
||||||
<!-- <mat-label>{{ 'login.fields.loginPw' | ucapI18n }}</mat-label> -->
|
|
||||||
<input
|
|
||||||
matInput
|
|
||||||
type="password"
|
|
||||||
[formControl]="loginPwFormControl"
|
|
||||||
placeholder="{{ 'login.fields.loginPw' | ucapI18n }}"
|
|
||||||
#loginPw
|
|
||||||
/>
|
|
||||||
</mat-form-field>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="error-container">
|
|
||||||
<mat-error
|
|
||||||
*ngIf="
|
|
||||||
companyCodeFormControl.dirty &&
|
|
||||||
companyCodeFormControl.invalid &&
|
|
||||||
companyCodeFormControl.hasError('required')
|
|
||||||
"
|
|
||||||
>
|
|
||||||
{{ 'login.errors.requireCompany' | ucapI18n }}
|
|
||||||
</mat-error>
|
|
||||||
<mat-error
|
|
||||||
*ngIf="
|
|
||||||
loginIdFormControl.dirty &&
|
|
||||||
loginIdFormControl.invalid &&
|
|
||||||
loginIdFormControl.hasError('required')
|
|
||||||
"
|
|
||||||
>
|
|
||||||
{{ 'login.errors.requireLoginId' | ucapI18n }}
|
|
||||||
</mat-error>
|
|
||||||
<mat-error
|
|
||||||
*ngIf="
|
|
||||||
loginPwFormControl.dirty &&
|
|
||||||
loginPwFormControl.invalid &&
|
|
||||||
loginPwFormControl.hasError('required')
|
|
||||||
"
|
|
||||||
>
|
|
||||||
{{ 'login.errors.requireLoginPw' | ucapI18n }}
|
|
||||||
</mat-error>
|
|
||||||
<mat-error *ngIf="loginFailed">
|
|
||||||
{{ 'login.errors.failed' | ucapI18n }}
|
|
||||||
</mat-error>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button
|
|
||||||
mat-raised-button
|
|
||||||
class="login-input-submit"
|
|
||||||
aria-label="LOG IN"
|
|
||||||
[disabled]="
|
|
||||||
loginForm.invalid ||
|
|
||||||
disable ||
|
|
||||||
(!!loginTry && !!loginTry.remainTimeForNextTry)
|
|
||||||
"
|
|
||||||
(click)="onClickLogin()"
|
|
||||||
>
|
|
||||||
<ng-container
|
|
||||||
*ngIf="!processing && (!loginTry || !loginTry.remainTimeForNextTry)"
|
|
||||||
>
|
|
||||||
{{ 'login.labels.doLogin' | ucapI18n }}
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<ng-container *ngIf="!!loginTry && !!loginTry.remainTimeForNextTry">
|
|
||||||
{{ 'login.errors.attemptsExceeded' | ucapI18n }}
|
|
||||||
(
|
|
||||||
{{
|
|
||||||
moment
|
|
||||||
.utc(
|
|
||||||
moment
|
|
||||||
.duration(loginTry.remainTimeForNextTry, 'seconds')
|
|
||||||
.asMilliseconds()
|
|
||||||
)
|
|
||||||
.format('mm:ss')
|
|
||||||
}}
|
|
||||||
)
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<mat-spinner
|
|
||||||
*ngIf="processing && (!loginTry || !loginTry.remainTimeForNextTry)"
|
|
||||||
>
|
|
||||||
</mat-spinner>
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<ng-content select="[ucapAuthenticationLogin='footer']"></ng-content>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,160 +0,0 @@
|
||||||
@import '../../../../../assets/scss/components';
|
|
||||||
|
|
||||||
.login-box {
|
|
||||||
@extend %clearfix;
|
|
||||||
padding: 0 0 45px;
|
|
||||||
width: 420px;
|
|
||||||
margin: auto;
|
|
||||||
text-align: center;
|
|
||||||
flex-basis: auto;
|
|
||||||
align-items: center;
|
|
||||||
.logo-img {
|
|
||||||
display: block;
|
|
||||||
text-align: center;
|
|
||||||
img {
|
|
||||||
margin-bottom: 7px;
|
|
||||||
vertical-align: top;
|
|
||||||
@include screen(mid) {
|
|
||||||
width: 120px;
|
|
||||||
}
|
|
||||||
@include screen(xs) {
|
|
||||||
width: 100px;
|
|
||||||
margin-bottom: 6px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@extend %guideline;
|
|
||||||
|
|
||||||
.login-content {
|
|
||||||
@extend %guideline2; //Guide Line2
|
|
||||||
margin: 30px auto 0;
|
|
||||||
.login-input-area {
|
|
||||||
border: 1px solid #cccccc;
|
|
||||||
border-radius: 2px;
|
|
||||||
width: 100%;
|
|
||||||
max-width: 420px;
|
|
||||||
min-width: 150px;
|
|
||||||
height: 60px;
|
|
||||||
background-color: $white;
|
|
||||||
margin-top: 10px;
|
|
||||||
&.login-select-form {
|
|
||||||
height: 60px;
|
|
||||||
line-height: 60px;
|
|
||||||
padding: 0 16px;
|
|
||||||
@include screen(mid) {
|
|
||||||
height: 50px;
|
|
||||||
line-height: 50px;
|
|
||||||
}
|
|
||||||
@include screen(xs) {
|
|
||||||
height: 42px;
|
|
||||||
line-height: 42px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&:first-of-type {
|
|
||||||
margin-top: 0px;
|
|
||||||
}
|
|
||||||
&.idpass-type {
|
|
||||||
padding-left: 50px;
|
|
||||||
position: relative;
|
|
||||||
&::before {
|
|
||||||
font-family: 'material Icons';
|
|
||||||
font-size: 24px;
|
|
||||||
text-align: center;
|
|
||||||
line-height: 60px;
|
|
||||||
content: 'perm_identity';
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 16px;
|
|
||||||
@include screen(mid) {
|
|
||||||
line-height: 50px;
|
|
||||||
}
|
|
||||||
@include screen(xs) {
|
|
||||||
line-height: 42px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.pass-type {
|
|
||||||
&::before {
|
|
||||||
content: 'https';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.login-idpass-txt {
|
|
||||||
width: 368px;
|
|
||||||
height: 60px;
|
|
||||||
line-height: 60px;
|
|
||||||
font-size: 14px;
|
|
||||||
@include screen(mid) {
|
|
||||||
width: 358 - 60 + px;
|
|
||||||
height: 50px;
|
|
||||||
line-height: 50px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
@include screen(xs) {
|
|
||||||
width: 308 - 60 + px;
|
|
||||||
font-size: 14px;
|
|
||||||
height: 42px;
|
|
||||||
line-height: 42px;
|
|
||||||
}
|
|
||||||
input {
|
|
||||||
font-size: 18px;
|
|
||||||
line-height: 58px;
|
|
||||||
margin-top: 0;
|
|
||||||
vertical-align: top;
|
|
||||||
background-color: $white;
|
|
||||||
padding: 0 10px 0 5px;
|
|
||||||
@include screen(mid) {
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: 48px;
|
|
||||||
}
|
|
||||||
@include screen(xs) {
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 40px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@include screen(mid) {
|
|
||||||
margin-top: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.login-input-submit {
|
|
||||||
width: 100%;
|
|
||||||
height: 60px;
|
|
||||||
background-color: $black;
|
|
||||||
border-radius: 2px;
|
|
||||||
color: $white;
|
|
||||||
font-size: 20px;
|
|
||||||
@include font-family($font-semibold);
|
|
||||||
border: 0;
|
|
||||||
margin-top: 12px;
|
|
||||||
font-weight: 600;
|
|
||||||
cursor: pointer;
|
|
||||||
@include screen(mid) {
|
|
||||||
margin-top: 8px;
|
|
||||||
font-size: 16px;
|
|
||||||
height: 50px;
|
|
||||||
}
|
|
||||||
@include screen(xs) {
|
|
||||||
font-size: 14px;
|
|
||||||
height: 42px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@include screen(mid) {
|
|
||||||
margin-top: 23px;
|
|
||||||
width: 350px;
|
|
||||||
.login-input-area {
|
|
||||||
height: 50px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@include screen(xs) {
|
|
||||||
margin-top: 23px;
|
|
||||||
width: 300px;
|
|
||||||
.login-input-area {
|
|
||||||
height: 42px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.login-company {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
|
@ -1,92 +0,0 @@
|
||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { LoginComponent } from './login.component';
|
|
||||||
import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
|
|
||||||
import { CommonModule } from '@angular/common';
|
|
||||||
import { ChangeDetectorRef } from '@angular/core';
|
|
||||||
import { I18nService, UCAP_I18N_NAMESPACE } from '@ucap/ng-i18n';
|
|
||||||
import { AuthenticationUiModule } from '../authentication-ui.module';
|
|
||||||
import { MatSelectModule } from '@angular/material/select';
|
|
||||||
import { Company } from '@ucap/api-external';
|
|
||||||
import { LogService } from '@ucap/ng-logger';
|
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
|
||||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
|
||||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
|
||||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
|
||||||
import { MatInputModule } from '@angular/material/input';
|
|
||||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
|
||||||
|
|
||||||
describe('ui::authentication::LoginComponent', () => {
|
|
||||||
let component: LoginComponent;
|
|
||||||
let fixture: ComponentFixture<LoginComponent>;
|
|
||||||
|
|
||||||
beforeEach(async(() => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
imports: [
|
|
||||||
BrowserModule,
|
|
||||||
BrowserAnimationsModule,
|
|
||||||
|
|
||||||
CommonModule,
|
|
||||||
ReactiveFormsModule,
|
|
||||||
|
|
||||||
MatButtonModule,
|
|
||||||
MatCheckboxModule,
|
|
||||||
MatFormFieldModule,
|
|
||||||
MatIconModule,
|
|
||||||
MatInputModule,
|
|
||||||
MatProgressSpinnerModule,
|
|
||||||
MatSelectModule
|
|
||||||
],
|
|
||||||
providers: [
|
|
||||||
AuthenticationUiModule,
|
|
||||||
// { provide: FormBuilder, useValue: new FormBuilder() },
|
|
||||||
// { provide: ChangeDetectorRef, useValue: ChangeDetectorRef },
|
|
||||||
{ provide: I18nService, useValue: new I18nService(new LogService({})) },
|
|
||||||
{
|
|
||||||
provide: UCAP_I18N_NAMESPACE,
|
|
||||||
useValue: 'authentication'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}).compileComponents();
|
|
||||||
}));
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
fixture = TestBed.createComponent(LoginComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
component.companyList = [
|
|
||||||
{ companyName: 'LG CNS', companyCode: 'GUC100' },
|
|
||||||
{ companyName: 'LG UCAP', companyCode: 'GUC101' }
|
|
||||||
] as Company[];
|
|
||||||
component.loginId = 'test';
|
|
||||||
component.companyCode = 'GUC100';
|
|
||||||
fixture.detectChanges();
|
|
||||||
|
|
||||||
component.ngOnInit();
|
|
||||||
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('login', (done) => {
|
|
||||||
component.companyList = [
|
|
||||||
{ companyName: 'LG CNS', companyCode: 'GUC100' },
|
|
||||||
{ companyName: 'LG UCAP', companyCode: 'GUC101' }
|
|
||||||
] as Company[];
|
|
||||||
component.loginId = 'test';
|
|
||||||
component.companyCode = 'GUC100';
|
|
||||||
|
|
||||||
component.ngOnInit();
|
|
||||||
|
|
||||||
component.login.subscribe((value) => {
|
|
||||||
console.log(value);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
|
|
||||||
component.onClickLogin();
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,110 +0,0 @@
|
||||||
import moment from 'moment';
|
|
||||||
|
|
||||||
import {
|
|
||||||
Component,
|
|
||||||
OnInit,
|
|
||||||
Input,
|
|
||||||
Output,
|
|
||||||
EventEmitter,
|
|
||||||
ViewChild,
|
|
||||||
ElementRef,
|
|
||||||
ChangeDetectorRef
|
|
||||||
} from '@angular/core';
|
|
||||||
import {
|
|
||||||
FormGroup,
|
|
||||||
FormBuilder,
|
|
||||||
Validators,
|
|
||||||
FormControl,
|
|
||||||
ValidatorFn
|
|
||||||
} from '@angular/forms';
|
|
||||||
import { Company } from '@ucap/api-external';
|
|
||||||
import { LoginTry } from '@ucap/pi';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'ucap-authentication-login-local',
|
|
||||||
templateUrl: './login.component.html',
|
|
||||||
styleUrls: ['./login.component.scss']
|
|
||||||
})
|
|
||||||
export class LoginComponent implements OnInit {
|
|
||||||
@Input()
|
|
||||||
companyList: Company[];
|
|
||||||
|
|
||||||
@Input()
|
|
||||||
fixedCompanyCode: string;
|
|
||||||
|
|
||||||
@Input()
|
|
||||||
companyCode: string;
|
|
||||||
|
|
||||||
@Input()
|
|
||||||
loginId: string;
|
|
||||||
|
|
||||||
@Input()
|
|
||||||
disable = false;
|
|
||||||
|
|
||||||
@Input()
|
|
||||||
processing = false;
|
|
||||||
|
|
||||||
@Input()
|
|
||||||
loginTry: LoginTry;
|
|
||||||
|
|
||||||
@Output()
|
|
||||||
login = new EventEmitter<{
|
|
||||||
companyCode: string;
|
|
||||||
loginId: string;
|
|
||||||
loginPw: string;
|
|
||||||
notValid: () => void;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
@ViewChild('loginPw', { static: true }) loginPwElementRef: ElementRef;
|
|
||||||
|
|
||||||
loginForm: FormGroup;
|
|
||||||
companyCodeFormControl = new FormControl('');
|
|
||||||
loginIdFormControl = new FormControl('');
|
|
||||||
loginPwFormControl = new FormControl('');
|
|
||||||
loginFailed = false;
|
|
||||||
|
|
||||||
moment = moment;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private formBuilder: FormBuilder,
|
|
||||||
private changeDetectorRef: ChangeDetectorRef
|
|
||||||
) {}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
const companyCodeValidators: ValidatorFn[] = [Validators.required];
|
|
||||||
this.companyCodeFormControl.setValidators(companyCodeValidators);
|
|
||||||
if (!!this.fixedCompanyCode) {
|
|
||||||
this.companyCodeFormControl.setValue(this.fixedCompanyCode);
|
|
||||||
}
|
|
||||||
if (!!this.companyCode) {
|
|
||||||
this.companyCodeFormControl.setValue(this.companyCode);
|
|
||||||
}
|
|
||||||
const loginIdValidators: ValidatorFn[] = [Validators.required];
|
|
||||||
this.loginIdFormControl.setValidators(loginIdValidators);
|
|
||||||
if (!!this.loginId) {
|
|
||||||
this.loginIdFormControl.setValue(this.loginId);
|
|
||||||
}
|
|
||||||
const loginPwValidators: ValidatorFn[] = [Validators.required];
|
|
||||||
this.loginPwFormControl.setValidators(loginPwValidators);
|
|
||||||
|
|
||||||
this.loginForm = this.formBuilder.group({
|
|
||||||
companyCodeFormControl: this.companyCodeFormControl,
|
|
||||||
loginIdFormControl: this.loginIdFormControl,
|
|
||||||
loginPwFormControl: this.loginPwFormControl
|
|
||||||
});
|
|
||||||
|
|
||||||
this.changeDetectorRef.detectChanges();
|
|
||||||
}
|
|
||||||
|
|
||||||
onClickLogin() {
|
|
||||||
this.login.emit({
|
|
||||||
companyCode: this.loginForm.get('companyCodeFormControl').value,
|
|
||||||
loginId: this.loginForm.get('loginIdFormControl').value,
|
|
||||||
loginPw: this.loginForm.get('loginPwFormControl').value,
|
|
||||||
notValid: () => {
|
|
||||||
this.loginFailed = true;
|
|
||||||
this.loginPwElementRef.nativeElement.focus();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,67 +0,0 @@
|
||||||
<div class="login-section-container">
|
|
||||||
<ucap-authentication-login-local
|
|
||||||
[companyList]="companyList"
|
|
||||||
[fixedCompanyCode]="fixedCompanyCode"
|
|
||||||
[companyCode]="userStore?.companyCode"
|
|
||||||
[loginId]="userStore?.loginId"
|
|
||||||
[disable]="disableLoginForm"
|
|
||||||
[processing]="loginProcessing"
|
|
||||||
[loginTry]="loginTry"
|
|
||||||
(login)="onLogin($event)"
|
|
||||||
>
|
|
||||||
<div ucapAuthenticationLogin="header">
|
|
||||||
<div class="logo-img">
|
|
||||||
<img src="../../../assets/images/logo_140.png" alt="" />
|
|
||||||
</div>
|
|
||||||
<h1>Welcome to Messenger</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div ucapAuthenticationLogin="footer">
|
|
||||||
<div class="login-chk-area">
|
|
||||||
<div>
|
|
||||||
<mat-checkbox
|
|
||||||
#chkUseRememberMe
|
|
||||||
*ngIf="useRememberMe"
|
|
||||||
aria-label="Remember Me"
|
|
||||||
[checked]="!!userStore && userStore.rememberMe"
|
|
||||||
>
|
|
||||||
{{ 'login.labels.rememberMe' | ucapI18n }}
|
|
||||||
</mat-checkbox>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<mat-checkbox
|
|
||||||
#chkUseAutoLogin
|
|
||||||
*ngIf="useAutoLogin"
|
|
||||||
aria-label="Auto Login"
|
|
||||||
[checked]="
|
|
||||||
!!userStore &&
|
|
||||||
!!userStore.settings &&
|
|
||||||
!!userStore.settings.general &&
|
|
||||||
userStore.settings.general.autoLogin
|
|
||||||
"
|
|
||||||
>
|
|
||||||
{{ 'login.labels.autoLogin' | ucapI18n }}
|
|
||||||
</mat-checkbox>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="login-pass-info">
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<a href="">{{ 'login.labels.forgotPassword' | ucapI18n }}</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="" class="fir-pass">{{
|
|
||||||
'login.labels.resetPassword' | ucapI18n
|
|
||||||
}}</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="login-button-area">
|
|
||||||
<button type="button">
|
|
||||||
{{ 'login.labels.notesOnUse' | ucapI18n }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ucap-authentication-login-local>
|
|
||||||
</div>
|
|
|
@ -1,117 +0,0 @@
|
||||||
@import '../../../../assets/scss/components';
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
@include font-family($font-light);
|
|
||||||
font-size: 24px;
|
|
||||||
text-align: center;
|
|
||||||
color: $txt-color01;
|
|
||||||
font-weight: 600;
|
|
||||||
line-height: 1.2;
|
|
||||||
@include screen(mid) {
|
|
||||||
font-size: 19px;
|
|
||||||
}
|
|
||||||
@include screen(xs) {
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.login-section-container {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login-chk-area {
|
|
||||||
margin-top: 6px;
|
|
||||||
font-size: 13px;
|
|
||||||
text-align: left;
|
|
||||||
@include screen(xs) {
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.login-pass-info {
|
|
||||||
overflow: hidden;
|
|
||||||
margin-top: 83px;
|
|
||||||
ul {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
li {
|
|
||||||
height: 24px;
|
|
||||||
position: relative;
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
padding: 0 12% 0 8%;
|
|
||||||
&::before {
|
|
||||||
content: '';
|
|
||||||
height: 11px;
|
|
||||||
width: 1px;
|
|
||||||
display: flex;
|
|
||||||
background-color: $gray-re4a;
|
|
||||||
position: absolute;
|
|
||||||
top: 6.5px;
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
&:first-child {
|
|
||||||
padding-left: 0;
|
|
||||||
&::before {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&:last-child {
|
|
||||||
padding-right: 0;
|
|
||||||
}
|
|
||||||
a {
|
|
||||||
line-height: 24px;
|
|
||||||
font-size: 12px;
|
|
||||||
color: $gray-re4a;
|
|
||||||
padding-left: 34px;
|
|
||||||
position: relative;
|
|
||||||
white-space: nowrap;
|
|
||||||
&::before {
|
|
||||||
font-family: 'material Icons';
|
|
||||||
font-size: 18px;
|
|
||||||
text-align: center;
|
|
||||||
content: 'search';
|
|
||||||
color: $white;
|
|
||||||
display: block;
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
border-radius: 50%;
|
|
||||||
background-color: $black;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
&.fir-pass {
|
|
||||||
&::before {
|
|
||||||
content: 'sync';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.login-button-area {
|
|
||||||
margin-top: 14px;
|
|
||||||
@include screen(xs) {
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
button {
|
|
||||||
border: 0;
|
|
||||||
margin: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 46px;
|
|
||||||
border-radius: 4px;
|
|
||||||
background-color: #e0e3e7;
|
|
||||||
font-size: 12px;
|
|
||||||
color: $gray-re4a;
|
|
||||||
cursor: pointer;
|
|
||||||
@include screen(mid) {
|
|
||||||
height: 38px;
|
|
||||||
}
|
|
||||||
@include screen(xs) {
|
|
||||||
height: 34px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,174 +0,0 @@
|
||||||
import { Subject } from 'rxjs';
|
|
||||||
import { take, takeUntil } from 'rxjs/operators';
|
|
||||||
|
|
||||||
import { Component, OnInit, OnDestroy, Input, ViewChild } from '@angular/core';
|
|
||||||
|
|
||||||
import { MatCheckbox } from '@angular/material/checkbox';
|
|
||||||
|
|
||||||
import { Store, select } from '@ngrx/store';
|
|
||||||
|
|
||||||
import { Company } from '@ucap/api-external';
|
|
||||||
import { LoginTry } from '@ucap/pi';
|
|
||||||
|
|
||||||
import { LogService } from '@ucap/ng-logger';
|
|
||||||
import { I18nService } from '@ucap/ng-i18n';
|
|
||||||
import { SessionStorageService } from '@ucap/ng-web-storage';
|
|
||||||
import { PiService } from '@ucap/ng-pi';
|
|
||||||
import { ProtocolService } from '@ucap/ng-protocol';
|
|
||||||
import { CompanyActions, CompanySelector } from '@ucap/ng-store-organization';
|
|
||||||
import { LoginActions } from '@ucap/ng-store-authentication';
|
|
||||||
|
|
||||||
import { UserStore } from '@app/models/user-store';
|
|
||||||
import { LoginSession } from '@app/models/login-session';
|
|
||||||
import { AppKey } from '@app/types/app-key.type';
|
|
||||||
import { AppAuthenticationService } from '@app/services/app-authentication.service';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-sections-account-login',
|
|
||||||
templateUrl: './login.section.component.html',
|
|
||||||
styleUrls: ['./login.section.component.scss']
|
|
||||||
})
|
|
||||||
export class LoginSectionComponent implements OnInit, OnDestroy {
|
|
||||||
@Input()
|
|
||||||
companyGroupCode: string;
|
|
||||||
|
|
||||||
@Input()
|
|
||||||
fixedCompanyCode: string;
|
|
||||||
|
|
||||||
@Input()
|
|
||||||
userStore: UserStore;
|
|
||||||
|
|
||||||
@Input()
|
|
||||||
useRememberMe: boolean;
|
|
||||||
|
|
||||||
@Input()
|
|
||||||
useAutoLogin: boolean;
|
|
||||||
|
|
||||||
@ViewChild('chkUseRememberMe', { static: false })
|
|
||||||
chkUseRememberMe: MatCheckbox;
|
|
||||||
|
|
||||||
@ViewChild('chkUseAutoLogin', { static: false })
|
|
||||||
chkUseAutoLogin: MatCheckbox;
|
|
||||||
|
|
||||||
loginSession: LoginSession;
|
|
||||||
companyList: Company[];
|
|
||||||
disableLoginForm = false;
|
|
||||||
loginProcessing = false;
|
|
||||||
loginTry: LoginTry;
|
|
||||||
|
|
||||||
private ngOnDestroySubject = new Subject<boolean>();
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private piService: PiService,
|
|
||||||
private protocolService: ProtocolService,
|
|
||||||
private sessionStorageService: SessionStorageService,
|
|
||||||
private i18nService: I18nService,
|
|
||||||
private store: Store<any>,
|
|
||||||
private appAuthenticationService: AppAuthenticationService,
|
|
||||||
private logService: LogService
|
|
||||||
) {}
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
this.ngOnDestroySubject = new Subject<boolean>();
|
|
||||||
|
|
||||||
this.appAuthenticationService
|
|
||||||
.getLoginSession$()
|
|
||||||
.pipe(takeUntil(this.ngOnDestroySubject))
|
|
||||||
.subscribe((loginSession) => (this.loginSession = loginSession));
|
|
||||||
|
|
||||||
this.sessionStorageService
|
|
||||||
.get$<LoginTry>(AppKey.LoginTry)
|
|
||||||
.pipe(takeUntil(this.ngOnDestroySubject))
|
|
||||||
.subscribe((loginTry) => (this.loginTry = loginTry));
|
|
||||||
|
|
||||||
this.protocolService.disconnect();
|
|
||||||
|
|
||||||
this.store.dispatch(
|
|
||||||
CompanyActions.companies({
|
|
||||||
req: { companyGroupCode: this.companyGroupCode }
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
this.store
|
|
||||||
.pipe(
|
|
||||||
takeUntil(this.ngOnDestroySubject),
|
|
||||||
select(CompanySelector.companyList)
|
|
||||||
)
|
|
||||||
.subscribe((companyList) => {
|
|
||||||
this.companyList = companyList;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
|
||||||
if (!!this.ngOnDestroySubject) {
|
|
||||||
this.ngOnDestroySubject.complete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onLogin(event: {
|
|
||||||
companyCode: string;
|
|
||||||
loginId: string;
|
|
||||||
loginPw: string;
|
|
||||||
notValid: () => void;
|
|
||||||
}) {
|
|
||||||
const useRememberMe: boolean = this.chkUseRememberMe.checked;
|
|
||||||
const useAutoLogin: boolean = this.chkUseAutoLogin.checked;
|
|
||||||
|
|
||||||
this.disableLoginForm = true;
|
|
||||||
this.loginProcessing = true;
|
|
||||||
|
|
||||||
this.piService
|
|
||||||
.login2({
|
|
||||||
companyCode: event.companyCode,
|
|
||||||
loginId: event.loginId,
|
|
||||||
loginPw: event.loginPw,
|
|
||||||
deviceType: this.loginSession.deviceType
|
|
||||||
})
|
|
||||||
.pipe(take(1))
|
|
||||||
.subscribe(
|
|
||||||
(res) => {
|
|
||||||
if ('success' !== res.status.toLowerCase()) {
|
|
||||||
this.onWebLoginFailure(event, res.status);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
this.store.dispatch(
|
|
||||||
LoginActions.webLoginSuccess({
|
|
||||||
companyCode: event.companyCode,
|
|
||||||
loginId: event.loginId,
|
|
||||||
loginPw: event.loginPw,
|
|
||||||
autoLogin: useAutoLogin,
|
|
||||||
rememberMe: useRememberMe,
|
|
||||||
login2Response: res
|
|
||||||
})
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
(error) => {
|
|
||||||
this.onWebLoginFailure(event, error);
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
this.disableLoginForm = false;
|
|
||||||
this.loginProcessing = false;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
onClickForgotPassword(lng: string) {
|
|
||||||
this.i18nService.changeLanguage(lng);
|
|
||||||
}
|
|
||||||
|
|
||||||
private onWebLoginFailure(
|
|
||||||
event: {
|
|
||||||
companyCode: string;
|
|
||||||
loginId: string;
|
|
||||||
loginPw: string;
|
|
||||||
notValid: () => void;
|
|
||||||
},
|
|
||||||
error: any
|
|
||||||
) {
|
|
||||||
this.store.dispatch(LoginActions.webLoginFailure({ error }));
|
|
||||||
|
|
||||||
event.notValid();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -21,18 +21,28 @@ import { MatTreeModule } from '@angular/material/tree';
|
||||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||||
import { MatStepperModule } from '@angular/material/stepper';
|
import { MatStepperModule } from '@angular/material/stepper';
|
||||||
|
import { MatDividerModule } from '@angular/material/divider';
|
||||||
|
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
||||||
|
import { MatRadioModule } from '@angular/material/radio';
|
||||||
|
import { MatTabsModule } from '@angular/material/tabs';
|
||||||
|
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
||||||
|
|
||||||
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
|
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
|
||||||
|
|
||||||
import { I18nModule, UCAP_I18N_NAMESPACE } from '@ucap/ng-i18n';
|
import { I18nModule, UCAP_I18N_NAMESPACE } from '@ucap/ng-i18n';
|
||||||
import { UiModule } from '@ucap/ng-ui';
|
import { UiModule } from '@ucap/ng-ui';
|
||||||
import { ChatUiModule } from '@ucap/ng-ui-chat';
|
import { ChatUiModule } from '@ucap/ng-ui-chat';
|
||||||
|
import { OrganizationUiModule } from '@ucap/ng-ui-organization';
|
||||||
|
import { AppOrganizationModule } from '@app/ucap/organization/organization.module';
|
||||||
|
|
||||||
import { AppChatModule } from '@app/ucap/chat/chat.module';
|
import { AppChatModule } from '@app/ucap/chat/chat.module';
|
||||||
import { AppLayoutsModule } from '@app/layouts/layouts.module';
|
import { AppLayoutsModule } from '@app/layouts/layouts.module';
|
||||||
import { AppGroupSectionModule } from '../group/group.section.module';
|
import { AppGroupSectionModule } from '../group/group.section.module';
|
||||||
|
|
||||||
import { COMPONENTS } from './components';
|
import { COMPONENTS } from './components';
|
||||||
import { DIALOGS } from './dialogs';
|
import { DIALOGS } from './dialogs';
|
||||||
|
import { DRAWERS } from './drawers';
|
||||||
|
import { AppGroupModule } from '@app/ucap/group/group.module';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -56,6 +66,11 @@ import { DIALOGS } from './dialogs';
|
||||||
MatTreeModule,
|
MatTreeModule,
|
||||||
MatTooltipModule,
|
MatTooltipModule,
|
||||||
MatStepperModule,
|
MatStepperModule,
|
||||||
|
MatDividerModule,
|
||||||
|
MatSlideToggleModule,
|
||||||
|
MatRadioModule,
|
||||||
|
MatTabsModule,
|
||||||
|
MatProgressBarModule,
|
||||||
|
|
||||||
PerfectScrollbarModule,
|
PerfectScrollbarModule,
|
||||||
ScrollingModule,
|
ScrollingModule,
|
||||||
|
@ -65,12 +80,16 @@ import { DIALOGS } from './dialogs';
|
||||||
|
|
||||||
AppLayoutsModule,
|
AppLayoutsModule,
|
||||||
AppGroupSectionModule,
|
AppGroupSectionModule,
|
||||||
|
AppOrganizationModule,
|
||||||
ChatUiModule,
|
ChatUiModule,
|
||||||
AppChatModule
|
OrganizationUiModule,
|
||||||
|
|
||||||
|
AppChatModule,
|
||||||
|
AppGroupModule
|
||||||
],
|
],
|
||||||
exports: [...COMPONENTS, ...DIALOGS],
|
exports: [...COMPONENTS, ...DIALOGS, ...DRAWERS],
|
||||||
declarations: [...COMPONENTS, ...DIALOGS],
|
declarations: [...COMPONENTS, ...DIALOGS, ...DRAWERS],
|
||||||
entryComponents: [...DIALOGS],
|
entryComponents: [...DIALOGS, ...DRAWERS],
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
provide: UCAP_I18N_NAMESPACE,
|
provide: UCAP_I18N_NAMESPACE,
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
<div class="search-container">
|
<div
|
||||||
|
class="search-container"
|
||||||
|
[ngClass]="!!isChatSearch ? 'chat-search-show' : ''"
|
||||||
|
>
|
||||||
<div class="searchbox ucap-mat-input-container">
|
<div class="searchbox ucap-mat-input-container">
|
||||||
<mat-form-field floatLabel="never" appearance="none" class="search-in-box">
|
<mat-form-field floatLabel="never" appearance="none" class="search-in-box">
|
||||||
<input
|
<mat-label>검색어를 입력하세요</mat-label>
|
||||||
matInput
|
<input matInput #searchWordInput type="text" />
|
||||||
#searchWordInput
|
|
||||||
type="text"
|
|
||||||
maxlength="20"
|
|
||||||
placeholder="솔루션"
|
|
||||||
/>
|
|
||||||
<button
|
<button
|
||||||
mat-button
|
mat-button
|
||||||
matSuffix
|
matSuffix
|
||||||
|
@ -17,7 +15,7 @@
|
||||||
class="btn-close"
|
class="btn-close"
|
||||||
color="accent"
|
color="accent"
|
||||||
>
|
>
|
||||||
<mat-icon>highlight_off</mat-icon>
|
<mat-icon>cancel</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<button
|
<button
|
||||||
|
@ -38,14 +36,16 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="search-result">
|
<div class="search-result">
|
||||||
<span class="text"><strong>N</strong>건의 검색결과가 있습니다.</span>
|
<span class="text"
|
||||||
<span class="result-count"><strong>1</strong>/N</span>
|
><strong class="txt-accent">N</strong>건의 검색결과가 있습니다.</span
|
||||||
|
>
|
||||||
|
<span class="result-count"><strong class="txt-accent">1</strong>/N</span>
|
||||||
<div class="btn-area">
|
<div class="btn-area">
|
||||||
<button mat-icon-button class="icon-button">
|
<button mat-icon-button class="icon-button">
|
||||||
<mat-icon>arrow_downward</mat-icon>
|
<mat-icon inline>arrow_downward</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<button mat-icon-button class="icon-button">
|
<button mat-icon-button class="icon-button">
|
||||||
<mat-icon>arrow_upward</mat-icon>
|
<mat-icon inline>arrow_upward</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
@import '~@ucap/lg-scss/mixins';
|
||||||
|
|
||||||
|
.search-container {
|
||||||
|
padding: 0 16px;
|
||||||
|
background-color: $white;
|
||||||
|
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
//position: relative;
|
||||||
|
//포지션 변경
|
||||||
|
position: absolute;
|
||||||
|
z-index: 5;
|
||||||
|
top: -80px;
|
||||||
|
width: 100%;
|
||||||
|
visibility: hidden;
|
||||||
|
transition: all 0.2s linear;
|
||||||
|
.searchbox {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 900px;
|
||||||
|
border: 1px solid $lipstick;
|
||||||
|
background-color: $white;
|
||||||
|
.search-in-box {
|
||||||
|
@include ucapMatFormField(0, 0, 100%, auto, auto, 38px, 38px);
|
||||||
|
padding-left: 10px;
|
||||||
|
.btn-close {
|
||||||
|
margin-top: 2px;
|
||||||
|
color: #fd78a1 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.btn-ico-search {
|
||||||
|
@include ucapMatButton(38px, 38px, 0, 20px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.search-result {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 900px;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
height: 40px;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
.text {
|
||||||
|
flex-grow: 1;
|
||||||
|
font-size: 0.857em;
|
||||||
|
color: $gray-re3;
|
||||||
|
strong {
|
||||||
|
font-size: 0.929em;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.result-count {
|
||||||
|
justify-self: self-end;
|
||||||
|
font-size: 0.929em;
|
||||||
|
}
|
||||||
|
.btn-area {
|
||||||
|
margin-right: -5px;
|
||||||
|
margin-left: 12px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
&:before {
|
||||||
|
content: '';
|
||||||
|
width: 1px;
|
||||||
|
height: 10px;
|
||||||
|
display: inline-block;
|
||||||
|
background-color: $gray-rec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//on
|
||||||
|
&.chat-search-show {
|
||||||
|
visibility: visible;
|
||||||
|
transition: all 0.2s linear;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,8 +5,10 @@ import {
|
||||||
Output,
|
Output,
|
||||||
EventEmitter,
|
EventEmitter,
|
||||||
ChangeDetectorRef,
|
ChangeDetectorRef,
|
||||||
ChangeDetectionStrategy
|
ChangeDetectionStrategy,
|
||||||
|
Input
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
|
import { SearchInfo } from '@app/pages/chat/models/search-info';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-sections-chat-chat-search',
|
selector: 'app-sections-chat-chat-search',
|
||||||
|
@ -15,20 +17,19 @@ import {
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class ChatSearchSectionComponent implements OnInit, OnDestroy {
|
export class ChatSearchSectionComponent implements OnInit, OnDestroy {
|
||||||
searchObj: any = {
|
@Input()
|
||||||
isSearch: false,
|
isChatSearch = false;
|
||||||
searchWord: ''
|
|
||||||
};
|
|
||||||
|
|
||||||
@Output()
|
@Output()
|
||||||
chatSearch = new EventEmitter<{
|
chatSearch = new EventEmitter<SearchInfo>();
|
||||||
isSearch: false;
|
|
||||||
searchWord: '';
|
|
||||||
}>();
|
|
||||||
|
|
||||||
@Output()
|
@Output()
|
||||||
closeChatSearch = new EventEmitter<void>();
|
closeChatSearch = new EventEmitter<void>();
|
||||||
|
|
||||||
|
searchObj: SearchInfo = {
|
||||||
|
isShowSearch: false,
|
||||||
|
searchWord: ''
|
||||||
|
};
|
||||||
constructor(private changeDetectorRef: ChangeDetectorRef) {}
|
constructor(private changeDetectorRef: ChangeDetectorRef) {}
|
||||||
|
|
||||||
ngOnInit(): void {}
|
ngOnInit(): void {}
|
||||||
|
@ -39,9 +40,9 @@ export class ChatSearchSectionComponent implements OnInit, OnDestroy {
|
||||||
alert(searchWord);
|
alert(searchWord);
|
||||||
|
|
||||||
this.searchObj = {
|
this.searchObj = {
|
||||||
isSearch: true,
|
isShowSearch: true,
|
||||||
searchWord
|
searchWord
|
||||||
};
|
} as SearchInfo;
|
||||||
this.chatSearch.emit(this.searchObj);
|
this.chatSearch.emit(this.searchObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,64 +0,0 @@
|
||||||
<div class="chat-list-item">
|
|
||||||
<div class="profileImage">
|
|
||||||
<img
|
|
||||||
class="thumbnail"
|
|
||||||
ucapImage
|
|
||||||
[base]="profileImageRoot"
|
|
||||||
[path]="profileImage"
|
|
||||||
[default]="defaultProfileImage"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="roomName">
|
|
||||||
{{ roomName }}
|
|
||||||
<strong *ngIf="roomInfo.roomType === RoomType.Multi"
|
|
||||||
>({{ roomInfo.joinUserCount }})</strong
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div class="lastMessage">{{ roomInfo.finalEventMessage }}</div>
|
|
||||||
<div class="date">{{ roomInfo.finalEventDate | ucapDate: 'LT' }}</div>
|
|
||||||
|
|
||||||
<span
|
|
||||||
class="noti-sum"
|
|
||||||
*ngIf="!!roomInfo.noReadCnt && roomInfo.noReadCnt > 0"
|
|
||||||
[matBadgeHidden]="roomInfo.noReadCnt === 0"
|
|
||||||
[matBadge]="roomInfo.noReadCnt"
|
|
||||||
matBadgeOverlap="true"
|
|
||||||
matBadgeColor="accent"
|
|
||||||
matBadgePosition="below after"
|
|
||||||
></span>
|
|
||||||
|
|
||||||
<button
|
|
||||||
mat-icon-button
|
|
||||||
aria-label="room-menu"
|
|
||||||
*ngIf="!checkable"
|
|
||||||
[matMenuTriggerFor]="roomMenu"
|
|
||||||
(click)="$event.stopPropagation()"
|
|
||||||
>
|
|
||||||
<mat-icon>more_vert</mat-icon>
|
|
||||||
</button>
|
|
||||||
<mat-checkbox
|
|
||||||
*ngIf="checkable"
|
|
||||||
#checkbox
|
|
||||||
[checked]="checked"
|
|
||||||
(change)="onToggleItem(checkbox.checked)"
|
|
||||||
(click)="$event.stopPropagation()"
|
|
||||||
class="group-check"
|
|
||||||
>
|
|
||||||
</mat-checkbox>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<mat-menu #roomMenu="matMenu">
|
|
||||||
<span class="manu-title">{{ roomName }}</span>
|
|
||||||
<button mat-menu-item>
|
|
||||||
<mat-icon>dialpad</mat-icon>
|
|
||||||
<span>대화방 열기</span>
|
|
||||||
</button>
|
|
||||||
<button mat-menu-item>
|
|
||||||
<mat-icon>dialpad</mat-icon>
|
|
||||||
<span>알림 해제</span>
|
|
||||||
</button>
|
|
||||||
<button mat-menu-item>
|
|
||||||
<mat-icon>dialpad</mat-icon>
|
|
||||||
<span>대화방 나가기</span>
|
|
||||||
</button>
|
|
||||||
</mat-menu>
|
|
|
@ -1,25 +0,0 @@
|
||||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { ChatListItemComponent } from './chat-list-item.component';
|
|
||||||
|
|
||||||
describe('ChatListItemComponent', () => {
|
|
||||||
let component: ChatListItemComponent;
|
|
||||||
let fixture: ComponentFixture<ChatListItemComponent>;
|
|
||||||
|
|
||||||
beforeEach(async(() => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
declarations: [ ChatListItemComponent ]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
}));
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
fixture = TestBed.createComponent(ChatListItemComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,63 +0,0 @@
|
||||||
import {
|
|
||||||
Component,
|
|
||||||
OnInit,
|
|
||||||
ChangeDetectionStrategy,
|
|
||||||
Input,
|
|
||||||
OnDestroy,
|
|
||||||
EventEmitter,
|
|
||||||
Output,
|
|
||||||
ChangeDetectorRef
|
|
||||||
} from '@angular/core';
|
|
||||||
import { RoomInfo, RoomType } from '@ucap/protocol-room';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-chat-list-item',
|
|
||||||
templateUrl: './chat-list-item.component.html',
|
|
||||||
styleUrls: ['./chat-list-item.component.scss'],
|
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
|
||||||
})
|
|
||||||
export class ChatListItemComponent implements OnInit, OnDestroy {
|
|
||||||
@Input()
|
|
||||||
roomInfo: RoomInfo;
|
|
||||||
|
|
||||||
@Input()
|
|
||||||
profileImageRoot: string;
|
|
||||||
|
|
||||||
@Input()
|
|
||||||
defaultProfileImage: string;
|
|
||||||
|
|
||||||
@Input()
|
|
||||||
profileImage: string;
|
|
||||||
|
|
||||||
@Input()
|
|
||||||
roomName: string;
|
|
||||||
|
|
||||||
@Input()
|
|
||||||
checkable = false;
|
|
||||||
|
|
||||||
@Input()
|
|
||||||
checked = false;
|
|
||||||
|
|
||||||
@Output()
|
|
||||||
toggleItem = new EventEmitter<{
|
|
||||||
checked: boolean;
|
|
||||||
roomInfo: RoomInfo;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
RoomType = RoomType;
|
|
||||||
|
|
||||||
constructor(private changeDetectorRef: ChangeDetectorRef) {}
|
|
||||||
|
|
||||||
ngOnInit(): void {}
|
|
||||||
|
|
||||||
ngOnDestroy(): void {}
|
|
||||||
|
|
||||||
onToggleItem(value: boolean): void {
|
|
||||||
this.toggleItem.emit({
|
|
||||||
checked: value,
|
|
||||||
roomInfo: this.roomInfo
|
|
||||||
});
|
|
||||||
|
|
||||||
this.changeDetectorRef.detectChanges();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
<div class="ucap-group-expansion-container" fxFlexFill>
|
|
||||||
<cdk-virtual-scroll-viewport #cvsvList perfectScrollbar fxFlexFill>
|
|
||||||
<ng-container
|
|
||||||
*cdkVirtualFor="
|
|
||||||
let node of dataSource.expandedData$;
|
|
||||||
templateCacheSize: 0
|
|
||||||
"
|
|
||||||
></ng-container>
|
|
||||||
|
|
||||||
<mat-tree #treeList [dataSource]="dataSource" [treeControl]="treeControl">
|
|
||||||
<mat-tree-node
|
|
||||||
*matTreeNodeDef="let node"
|
|
||||||
[attr.node-type]="node?.nodeType"
|
|
||||||
matRipple
|
|
||||||
>
|
|
||||||
<li>
|
|
||||||
<div>
|
|
||||||
<ng-container
|
|
||||||
[ngTemplateOutlet]="nodeTemplate"
|
|
||||||
[ngTemplateOutletContext]="{ $implicit: node?.node }"
|
|
||||||
></ng-container>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</mat-tree-node>
|
|
||||||
|
|
||||||
<mat-tree-node
|
|
||||||
*matTreeNodeDef="let node; when: isHeader"
|
|
||||||
class="tree-node-frame ucap-clickable"
|
|
||||||
[attr.node-type]="node?.nodeType"
|
|
||||||
matRipple
|
|
||||||
>
|
|
||||||
<li class="tree-node-header" matTreeNodeToggle>
|
|
||||||
<div class="path">
|
|
||||||
<button
|
|
||||||
mat-icon-button
|
|
||||||
[attr.aria-label]="'toggle '"
|
|
||||||
class="btn-toggle"
|
|
||||||
>
|
|
||||||
<mat-icon class="mat-icon-rtl-mirror">
|
|
||||||
{{
|
|
||||||
treeControl.isExpanded(node) ? 'expand_less' : 'expand_more'
|
|
||||||
}}
|
|
||||||
</mat-icon>
|
|
||||||
</button>
|
|
||||||
<div class="group-info">
|
|
||||||
<ng-container
|
|
||||||
[ngTemplateOutlet]="headerTemplate"
|
|
||||||
[ngTemplateOutletContext]="{ $implicit: node?.node }"
|
|
||||||
>
|
|
||||||
</ng-container>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<ul [class.group-tree-node-invisible]="!treeControl.isExpanded(node)">
|
|
||||||
<div *ngIf="treeControl.isExpanded(node)" class="boxnone">
|
|
||||||
<div class="vertical-line"></div>
|
|
||||||
<ng-container matTreeNodeOutlet></ng-container>
|
|
||||||
</div>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</mat-tree-node>
|
|
||||||
</mat-tree>
|
|
||||||
</cdk-virtual-scroll-viewport>
|
|
||||||
</div>
|
|
|
@ -1,177 +0,0 @@
|
||||||
import {
|
|
||||||
Component,
|
|
||||||
OnInit,
|
|
||||||
OnDestroy,
|
|
||||||
Input,
|
|
||||||
ViewChild,
|
|
||||||
ContentChild,
|
|
||||||
TemplateRef,
|
|
||||||
ChangeDetectionStrategy,
|
|
||||||
ChangeDetectorRef,
|
|
||||||
Directive
|
|
||||||
} from '@angular/core';
|
|
||||||
|
|
||||||
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
|
|
||||||
import { FlatTreeControl } from '@angular/cdk/tree';
|
|
||||||
|
|
||||||
import { MatTreeFlattener, MatTree } from '@angular/material/tree';
|
|
||||||
|
|
||||||
import { VirtualScrollTreeFlatDataSource } from '@ucap/ng-ui';
|
|
||||||
import { Subject } from 'rxjs';
|
|
||||||
import { takeUntil } from 'rxjs/operators';
|
|
||||||
import { PerfectScrollbarDirective } from 'ngx-perfect-scrollbar';
|
|
||||||
import { RoomInfo } from '@ucap/protocol-room';
|
|
||||||
|
|
||||||
export interface ChatGroupNode {
|
|
||||||
nodeType: string;
|
|
||||||
roomInfo?: RoomInfo;
|
|
||||||
children?: ChatGroupNode[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface FlatNode {
|
|
||||||
expandable: boolean;
|
|
||||||
level: number;
|
|
||||||
node: ChatGroupNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Directive({
|
|
||||||
selector: '[ucapChatExpansionNode]'
|
|
||||||
})
|
|
||||||
export class ExpansionNodeDirective {}
|
|
||||||
|
|
||||||
@Directive({
|
|
||||||
selector: '[ucapChatExpansionHeader]'
|
|
||||||
})
|
|
||||||
export class ExpansionHeaderDirective {}
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'ucap-chat-expansion',
|
|
||||||
templateUrl: './expansion.component.html',
|
|
||||||
styleUrls: ['./expansion.component.scss'],
|
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
|
||||||
})
|
|
||||||
export class ExpansionComponent implements OnInit, OnDestroy {
|
|
||||||
@Input()
|
|
||||||
set chatGroup(list: { division: string; roomList: RoomInfo[] }[]) {
|
|
||||||
if (!list || 0 === list.length) {
|
|
||||||
} else {
|
|
||||||
list.sort((a, b) =>
|
|
||||||
a.division < b.division ? 1 : a.division > b.division ? -1 : 0
|
|
||||||
);
|
|
||||||
|
|
||||||
for (const item of list) {
|
|
||||||
const nodeType = item.division;
|
|
||||||
const node: ChatGroupNode = {
|
|
||||||
nodeType,
|
|
||||||
children: []
|
|
||||||
};
|
|
||||||
|
|
||||||
item.roomList.sort((a, b) =>
|
|
||||||
a.finalEventDate < b.finalEventDate
|
|
||||||
? 1
|
|
||||||
: a.finalEventDate > b.finalEventDate
|
|
||||||
? -1
|
|
||||||
: 0
|
|
||||||
);
|
|
||||||
|
|
||||||
item.roomList.forEach((roomInfo) => {
|
|
||||||
node.children.push({
|
|
||||||
nodeType,
|
|
||||||
roomInfo
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!!this.nodeMap.get(item.division)) {
|
|
||||||
this.nodeMap[item.division].push(node);
|
|
||||||
} else {
|
|
||||||
this.nodeMap.set(item.division, [node]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.refreshNodes();
|
|
||||||
}
|
|
||||||
|
|
||||||
@ViewChild('treeList', { static: false })
|
|
||||||
treeList: MatTree<FlatNode>;
|
|
||||||
|
|
||||||
@ViewChild('cvsvList', { static: false })
|
|
||||||
cvsvList: CdkVirtualScrollViewport;
|
|
||||||
|
|
||||||
@ViewChild(PerfectScrollbarDirective, { static: false })
|
|
||||||
psDirectiveRef?: PerfectScrollbarDirective;
|
|
||||||
|
|
||||||
@ContentChild(ExpansionNodeDirective, {
|
|
||||||
read: TemplateRef,
|
|
||||||
static: false
|
|
||||||
})
|
|
||||||
nodeTemplate: TemplateRef<ExpansionNodeDirective>;
|
|
||||||
|
|
||||||
@ContentChild(ExpansionHeaderDirective, {
|
|
||||||
read: TemplateRef,
|
|
||||||
static: false
|
|
||||||
})
|
|
||||||
headerTemplate: TemplateRef<ExpansionHeaderDirective>;
|
|
||||||
|
|
||||||
treeControl: FlatTreeControl<FlatNode>;
|
|
||||||
treeFlattener: MatTreeFlattener<ChatGroupNode, FlatNode>;
|
|
||||||
dataSource: VirtualScrollTreeFlatDataSource<ChatGroupNode, FlatNode>;
|
|
||||||
|
|
||||||
private nodeMap: Map<string, ChatGroupNode[]> = new Map();
|
|
||||||
// tslint:disable-next-line: variable-name
|
|
||||||
private _ngOnDestroySubject: Subject<void>;
|
|
||||||
|
|
||||||
constructor(private changeDetectorRef: ChangeDetectorRef) {
|
|
||||||
this.treeControl = new FlatTreeControl<FlatNode>(
|
|
||||||
(node) => node.level,
|
|
||||||
(node) => node.expandable
|
|
||||||
);
|
|
||||||
|
|
||||||
this.treeFlattener = new MatTreeFlattener<ChatGroupNode, FlatNode>(
|
|
||||||
(node: ChatGroupNode, level: number) => {
|
|
||||||
return {
|
|
||||||
expandable: !!node.children && node.children.length > 0,
|
|
||||||
level,
|
|
||||||
nodeType: node.nodeType,
|
|
||||||
node
|
|
||||||
};
|
|
||||||
},
|
|
||||||
(node) => node.level,
|
|
||||||
(node) => node.expandable,
|
|
||||||
(node) => node.children
|
|
||||||
);
|
|
||||||
|
|
||||||
this.dataSource = new VirtualScrollTreeFlatDataSource<
|
|
||||||
ChatGroupNode,
|
|
||||||
FlatNode
|
|
||||||
>(this.treeControl, this.treeFlattener);
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
this._ngOnDestroySubject = new Subject();
|
|
||||||
|
|
||||||
this.dataSource.cdkVirtualScrollViewport = this.cvsvList;
|
|
||||||
this.treeControl.expansionModel.changed
|
|
||||||
.pipe(takeUntil(this._ngOnDestroySubject))
|
|
||||||
.subscribe(() => {
|
|
||||||
this.cvsvList.checkViewportSize();
|
|
||||||
this.psDirectiveRef.update();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
|
||||||
if (!!this._ngOnDestroySubject) {
|
|
||||||
this._ngOnDestroySubject.next();
|
|
||||||
this._ngOnDestroySubject.complete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isHeader = (_: number, node: FlatNode) => 0 === node.level;
|
|
||||||
|
|
||||||
private refreshNodes() {
|
|
||||||
const rootNode: ChatGroupNode[] = [];
|
|
||||||
this.nodeMap.forEach((node) => rootNode.push(...node));
|
|
||||||
|
|
||||||
this.dataSource.data = rootNode;
|
|
||||||
this.changeDetectorRef.detectChanges();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
import { ChatListItemComponent } from './chat-list-item.component';
|
|
||||||
import {
|
|
||||||
ExpansionComponent,
|
|
||||||
ExpansionNodeDirective,
|
|
||||||
ExpansionHeaderDirective
|
|
||||||
} from './expansion.component';
|
|
||||||
|
|
||||||
export const COMPONENTS = [ChatListItemComponent, ExpansionComponent];
|
|
||||||
|
|
||||||
export const DIRECTIVES = [ExpansionNodeDirective, ExpansionHeaderDirective];
|
|
|
@ -1,123 +1,159 @@
|
||||||
<ng-container [ngSwitch]="selectorType">
|
<div class="ucap-chat-input-container">
|
||||||
<app-chat-selector-sticker
|
<ng-container [ngSwitch]="selectorType">
|
||||||
*ngSwitchCase="SelectorType.STICKER"
|
<app-chat-selector-sticker
|
||||||
(selectedSticker)="onSelectedSticker($event)"
|
*ngSwitchCase="SelectorType.STICKER"
|
||||||
(closeSticker)="selectorType = SelectorType.EMPTY"
|
(selectedSticker)="onSelectedSticker($event)"
|
||||||
>
|
(closed)="selectorType = SelectorType.EMPTY"
|
||||||
</app-chat-selector-sticker>
|
>
|
||||||
|
</app-chat-selector-sticker>
|
||||||
|
|
||||||
<app-chat-selector-translation
|
<app-chat-selector-translation
|
||||||
*ngSwitchCase="SelectorType.TRANSLATION"
|
*ngSwitchCase="SelectorType.TRANSLATION"
|
||||||
></app-chat-selector-translation>
|
(closed)="
|
||||||
|
selectorType = SelectorType.EMPTY; translationPreviewInfo = null
|
||||||
|
"
|
||||||
|
[destLocale]="destLocale"
|
||||||
|
[simpleView]="translationSimpleview"
|
||||||
|
[preView]="translationPreview"
|
||||||
|
[translationPreviewInfo]="translationPreviewInfo"
|
||||||
|
(changeTranslationSimpleview)="onChangeTranslationSimpleView($event)"
|
||||||
|
(changeTranslationPreview)="onChangeTranslationPreView($event)"
|
||||||
|
(changeDestLocale)="onChangeDestLocale($event)"
|
||||||
|
(sendTranslationMessage)="onSendTranslationMessage($event)"
|
||||||
|
(translationMessage)="send()"
|
||||||
|
></app-chat-selector-translation>
|
||||||
|
|
||||||
<app-chat-selector-file-upload
|
<app-chat-selector-file-upload
|
||||||
#fileUploadSelector
|
#fileUploadSelector
|
||||||
*ngSwitchCase="SelectorType.FILEUPLOAD"
|
*ngSwitchCase="SelectorType.FILEUPLOAD"
|
||||||
>
|
(closed)="selectorType = SelectorType.EMPTY"
|
||||||
</app-chat-selector-file-upload>
|
>
|
||||||
|
</app-chat-selector-file-upload>
|
||||||
|
|
||||||
<app-chat-selector-email-send
|
<app-chat-selector-email-send
|
||||||
*ngSwitchCase="SelectorType.EMAILSENDER"
|
*ngSwitchCase="SelectorType.EMAILSENDER"
|
||||||
></app-chat-selector-email-send>
|
(sendEventEmail)="onSendEventEmail($event)"
|
||||||
</ng-container>
|
(closed)="selectorType = SelectorType.EMPTY"
|
||||||
|
></app-chat-selector-email-send>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
<div class="chat-form-area">
|
<div class="chat-form-area ucap-mat-input-container">
|
||||||
<mat-form-field
|
<mat-form-field
|
||||||
class="message-text"
|
class="message-text"
|
||||||
fxFlex
|
fxFlex
|
||||||
floatLabel="never"
|
floatLabel="never"
|
||||||
appearance="standard"
|
appearance="none"
|
||||||
>
|
>
|
||||||
<textarea
|
<mat-label>{{ 'chat:label.inputChatMessage' | ucapI18n }}</mat-label>
|
||||||
matInput
|
<!-- <textarea
|
||||||
#messageInput
|
matInput
|
||||||
placeholder=""
|
#messageInput
|
||||||
name="message"
|
name="message"
|
||||||
[matTextareaAutosize]="true"
|
[matTextareaAutosize]="true"
|
||||||
[matAutosizeMaxRows]="20"
|
(keydown.enter)="onKeydown($event)"
|
||||||
(keydown)="onKeydown($event)"
|
></textarea> -->
|
||||||
></textarea>
|
<input
|
||||||
</mat-form-field>
|
matInput
|
||||||
|
#messageInput
|
||||||
|
name="message"
|
||||||
|
(keydown.enter)="onKeydown($event)"
|
||||||
|
/>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
#fileInput
|
#fileInput
|
||||||
style="display: none;"
|
style="display: none;"
|
||||||
multiple
|
multiple
|
||||||
(change)="onChangeFileInput()"
|
(change)="onChangeFileInput()"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="button-area">
|
|
||||||
<button
|
<div class="button-area">
|
||||||
mat-button
|
<button
|
||||||
aria-label="attachFile"
|
mat-icon-button
|
||||||
matTooltipPosition="above"
|
aria-label="attachFile"
|
||||||
matTooltip="{{ 'label.attachFile' | ucapI18n }}"
|
matTooltipPosition="above"
|
||||||
(click)="clearSelector(); fileInput.click()"
|
matTooltip="{{ 'label.attachFile' | ucapI18n }}"
|
||||||
>
|
class="btn-icon-chat"
|
||||||
첨부파일
|
(click)="clearSelector(); fileInput.accept = '*.*'; fileInput.click()"
|
||||||
</button>
|
>
|
||||||
<button
|
<mat-icon>attach_file</mat-icon>
|
||||||
mat-button
|
</button>
|
||||||
aria-label="attachImage"
|
<button
|
||||||
matTooltipPosition="above"
|
mat-icon-button
|
||||||
matTooltip="{{ 'label.attachImage' | ucapI18n }}"
|
aria-label="attachImage"
|
||||||
(click)="onOpenSelector(SelectorType.EMPTY)"
|
matTooltipPosition="above"
|
||||||
>
|
matTooltip="{{ 'label.attachImage' | ucapI18n }}"
|
||||||
이미지
|
class="btn-icon-chat"
|
||||||
</button>
|
(click)="
|
||||||
<button
|
clearSelector(); fileInput.accept = 'image/*,video/*'; fileInput.click()
|
||||||
mat-button
|
"
|
||||||
aria-label="screenshot"
|
>
|
||||||
matTooltipPosition="above"
|
<mat-icon class="material-icons-outlined">image</mat-icon>
|
||||||
matTooltip="{{ 'label.screenshot' | ucapI18n }}"
|
</button>
|
||||||
(click)="onOpenSelector(SelectorType.EMPTY)"
|
<!-- <button
|
||||||
>
|
mat-icon-button
|
||||||
캡쳐 화면 전송
|
*ngIf="!!authRes && !!authRes.useCapturePcScreen"
|
||||||
</button>
|
aria-label="screenshot"
|
||||||
<button
|
matTooltipPosition="above"
|
||||||
mat-button
|
matTooltip="{{ 'label.screenshot' | ucapI18n }}"
|
||||||
aria-label="imoticon"
|
class="btn-icon-chat"
|
||||||
matTooltipPosition="above"
|
(click)="onOpenSelector(SelectorType.EMPTY)"
|
||||||
matTooltip="{{ 'label.imoticon' | ucapI18n }}"
|
>
|
||||||
(click)="onOpenSelector(SelectorType.STICKER)"
|
<mat-icon>filter_center_focus</mat-icon>
|
||||||
>
|
</button> -->
|
||||||
이모티콘
|
<button
|
||||||
</button>
|
mat-icon-button
|
||||||
<button
|
aria-label="imoticon"
|
||||||
mat-button
|
matTooltipPosition="above"
|
||||||
aria-label="emailSend"
|
matTooltip="{{ 'label.imoticon' | ucapI18n }}"
|
||||||
matTooltipPosition="above"
|
class="btn-icon-chat"
|
||||||
matTooltip="{{ 'label.emailSend' | ucapI18n }}"
|
(click)="onOpenSelector(SelectorType.STICKER)"
|
||||||
(click)="onOpenSelector(SelectorType.EMAILSENDER)"
|
>
|
||||||
>
|
<mat-icon>sentiment_satisfied</mat-icon>
|
||||||
대화내용 메일 전송
|
</button>
|
||||||
</button>
|
<button
|
||||||
<button
|
mat-icon-button
|
||||||
mat-button
|
*ngIf="!!authRes && !!authRes.canSendEmail"
|
||||||
aria-label="translation"
|
aria-label="emailSend"
|
||||||
matTooltipPosition="above"
|
matTooltipPosition="above"
|
||||||
matTooltip="{{ 'label.translation' | ucapI18n }}"
|
matTooltip="{{ 'label.emailSend' | ucapI18n }}"
|
||||||
(click)="onOpenSelector(SelectorType.TRANSLATION)"
|
class="btn-icon-chat"
|
||||||
>
|
(click)="onOpenSelector(SelectorType.EMAILSENDER)"
|
||||||
대화내용 번역
|
>
|
||||||
</button>
|
<mat-icon class="material-icons-outlined">drafts</mat-icon>
|
||||||
<button
|
</button>
|
||||||
mat-button
|
<button
|
||||||
aria-label="gams"
|
mat-icon-button
|
||||||
matTooltipPosition="above"
|
*ngIf="!!authRes && !!authRes.canTranslation"
|
||||||
matTooltip="{{ 'label.gams' | ucapI18n }}"
|
aria-label="translation"
|
||||||
(click)="onOpenSelector(SelectorType.EMPTY)"
|
matTooltipPosition="above"
|
||||||
>
|
matTooltip="{{ 'label.translation' | ucapI18n }}"
|
||||||
+GAMS
|
class="btn-icon-chat"
|
||||||
</button>
|
(click)="onOpenSelector(SelectorType.TRANSLATION)"
|
||||||
<button
|
>
|
||||||
mat-fab
|
<mat-icon>translate</mat-icon>
|
||||||
color="accent"
|
</button>
|
||||||
aria-label="send"
|
<!-- <button
|
||||||
matTooltip="{{ 'label.send' | ucapI18n }}"
|
mat-icon-button
|
||||||
(click)="send()"
|
*ngIf="!!authRes && !!authRes.useGams"
|
||||||
>
|
aria-label="gams"
|
||||||
<mat-icon>send</mat-icon>
|
matTooltipPosition="above"
|
||||||
</button>
|
matTooltip="{{ 'label.gams' | ucapI18n }}"
|
||||||
|
class="btn-icon-chat btn-icon-chat-gams"
|
||||||
|
(click)="onOpenSelector(SelectorType.EMPTY)"
|
||||||
|
>
|
||||||
|
<strong>+GAMS</strong>
|
||||||
|
</button> -->
|
||||||
|
<button
|
||||||
|
mat-mini-fab
|
||||||
|
class="btn-message-send"
|
||||||
|
aria-label="send"
|
||||||
|
matTooltip="{{ 'label.send' | ucapI18n }}"
|
||||||
|
(click)="send()"
|
||||||
|
>
|
||||||
|
<mat-icon>arrow_upward</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
@import '~@ucap/lg-scss/mixins';
|
||||||
|
|
||||||
|
.ucap-chat-input-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
border-top: 1px solid #ccc;
|
||||||
|
background-color: $white;
|
||||||
|
.chat-form-area {
|
||||||
|
max-height: 100%;
|
||||||
|
min-height: 20px;
|
||||||
|
background-color: $white;
|
||||||
|
padding-left: 30px;
|
||||||
|
font-size: 0.929em;
|
||||||
|
margin: 8px 0;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
@include screen(xs) {
|
||||||
|
padding-left: 16px;
|
||||||
|
}
|
||||||
|
textarea {
|
||||||
|
min-height: 22px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.button-area {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
height: 34px;
|
||||||
|
background-color: rgba(0, 0, 0, 0.02);
|
||||||
|
border-top: 1px solid #eeeeee;
|
||||||
|
padding: 0 16px;
|
||||||
|
flex: 0 0 0;
|
||||||
|
@include screen(xs) {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.btn-icon-chat {
|
||||||
|
@include ucapMatButton(34px, 34px, 0, 34px);
|
||||||
|
&.btn-icon-chat-gams {
|
||||||
|
width: 60px;
|
||||||
|
@include font-family($font-semibold);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.btn-message-send {
|
||||||
|
width: 38px;
|
||||||
|
height: 38px;
|
||||||
|
box-shadow: 0px 2px 2px 0 rgba(0, 0, 0, 0.3);
|
||||||
|
border: solid 3px #ffffff;
|
||||||
|
background-image: linear-gradient(225deg, #fadfaa 5%, #f92465 95%);
|
||||||
|
font-size: 1.714em;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 10;
|
||||||
|
bottom: 25px;
|
||||||
|
right: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
import { Subject, of, Observable, forkJoin } from 'rxjs';
|
import { Subject, of, merge } from 'rxjs';
|
||||||
import { takeUntil, map, catchError, take } from 'rxjs/operators';
|
import { takeUntil, map, catchError, take } from 'rxjs/operators';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -9,51 +9,68 @@ import {
|
||||||
ChangeDetectorRef,
|
ChangeDetectorRef,
|
||||||
Input,
|
Input,
|
||||||
ViewChild,
|
ViewChild,
|
||||||
ElementRef
|
ElementRef,
|
||||||
|
EventEmitter,
|
||||||
|
Output
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { Store, select } from '@ngrx/store';
|
|
||||||
import { Dictionary } from '@ngrx/entity';
|
|
||||||
|
|
||||||
|
import { Store, select } from '@ngrx/store';
|
||||||
|
|
||||||
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
|
|
||||||
|
import { StickerFilesInfo } from '@ucap/ng-core';
|
||||||
|
import { StatusCode, FileUploadItem } 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 { RoomInfo } from '@ucap/protocol-room';
|
||||||
import {
|
import {
|
||||||
SendRequest as SendEventRequest,
|
EventType,
|
||||||
EventType
|
MassTranslationEventJson,
|
||||||
|
TranslationEventJson
|
||||||
} from '@ucap/protocol-event';
|
} from '@ucap/protocol-event';
|
||||||
import { LoginResponse } from '@ucap/protocol-authentication';
|
import { LoginResponse } from '@ucap/protocol-authentication';
|
||||||
|
import { AuthResponse } from '@ucap/protocol-query';
|
||||||
|
import { User } from '@ucap/protocol-info';
|
||||||
|
|
||||||
import { ChattingActions } from '@ucap/ng-store-chat';
|
import { I18nService } from '@ucap/ng-i18n';
|
||||||
|
import { LogService } from '@ucap/ng-logger';
|
||||||
|
import { CommonApiService } from '@ucap/ng-api-common';
|
||||||
|
import { PiService } from '@ucap/ng-pi';
|
||||||
|
|
||||||
|
import { UserSelector } from '@ucap/ng-store-organization';
|
||||||
import {
|
import {
|
||||||
LoginSelector,
|
LoginSelector,
|
||||||
ConfigurationSelector
|
ConfigurationSelector,
|
||||||
|
AuthorizationSelector
|
||||||
} from '@ucap/ng-store-authentication';
|
} from '@ucap/ng-store-authentication';
|
||||||
import { StickerFilesInfo, KEY_STICKER_HISTORY } from '@ucap/ng-core';
|
import { ChattingSelector, RoomSelector } from '@ucap/ng-store-chat';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
AlertDialogComponent,
|
AlertDialogComponent,
|
||||||
AlertDialogData,
|
AlertDialogData,
|
||||||
AlertDialogResult
|
AlertDialogResult,
|
||||||
|
ConfirmDialogComponent,
|
||||||
|
ConfirmDialogData,
|
||||||
|
ConfirmDialogResult
|
||||||
} from '@ucap/ng-ui';
|
} from '@ucap/ng-ui';
|
||||||
import { I18nService } from '@ucap/ng-i18n';
|
|
||||||
import { LogService } from '@ucap/ng-logger';
|
|
||||||
|
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
|
||||||
import {
|
|
||||||
TranslationSaveResponse,
|
|
||||||
MassTalkSaveRequest,
|
|
||||||
FileTalkSaveResponse,
|
|
||||||
FileTalkSaveRequest
|
|
||||||
} from '@ucap/api-common';
|
|
||||||
import { environment } from '@environments';
|
|
||||||
import { LocalStorageService } from '@ucap/ng-web-storage';
|
|
||||||
import { CommonApiService } from '@ucap/ng-api-common';
|
|
||||||
import { LoginSession } from '@app/models/login-session';
|
import { LoginSession } from '@app/models/login-session';
|
||||||
import { AppAuthenticationService } from '@app/services/app-authentication.service';
|
import { AppAuthenticationService } from '@app/services/app-authentication.service';
|
||||||
import { StatusCode, FileUploadItem } from '@ucap/api';
|
|
||||||
import { AppFileService } from '@app/services/app-file.service';
|
import { AppFileService } from '@app/services/app-file.service';
|
||||||
import { VersionInfo2Response } from '@ucap/api-public';
|
|
||||||
import { FileUploadSelectorComponent } from '@app/ucap/chat/components/file-upload.selector.component';
|
import { FileUploadSelectorComponent } from '@app/ucap/chat/components/file-upload.selector.component';
|
||||||
import { FileUtil } from '@ucap/core';
|
|
||||||
import { AppChatService } from '@app/services/app-chat.service';
|
import { AppChatService } from '@app/services/app-chat.service';
|
||||||
|
|
||||||
|
import { environment } from '@environments';
|
||||||
|
|
||||||
export enum SelectorType {
|
export enum SelectorType {
|
||||||
EMPTY = '',
|
EMPTY = '',
|
||||||
STICKER = 'STICKER',
|
STICKER = 'STICKER',
|
||||||
|
@ -69,9 +86,17 @@ export enum SelectorType {
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class FormSectionComponent implements OnInit, OnDestroy {
|
export class FormSectionComponent implements OnInit, OnDestroy {
|
||||||
|
private roomIdSubject = new Subject<string>();
|
||||||
|
private ngOnDestroySubject: Subject<void> = new Subject();
|
||||||
@Input()
|
@Input()
|
||||||
set roomId(roomId: string) {
|
set roomId(roomId: string) {
|
||||||
this._roomId = roomId;
|
if (!!roomId && this.roomId !== roomId) {
|
||||||
|
this._roomId = roomId;
|
||||||
|
|
||||||
|
this.roomIdSubject.next(roomId);
|
||||||
|
|
||||||
|
this.initializeRoomData();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
get roomId(): string {
|
get roomId(): string {
|
||||||
return this._roomId;
|
return this._roomId;
|
||||||
|
@ -79,9 +104,17 @@ export class FormSectionComponent implements OnInit, OnDestroy {
|
||||||
// tslint:disable-next-line: variable-name
|
// tslint:disable-next-line: variable-name
|
||||||
_roomId: string;
|
_roomId: string;
|
||||||
|
|
||||||
|
@Output()
|
||||||
|
changeTranslationSimpleview = new EventEmitter<boolean>();
|
||||||
|
|
||||||
|
@Output()
|
||||||
|
eventSendTrigger = new EventEmitter<any>();
|
||||||
|
|
||||||
versionInfo2Res: VersionInfo2Response;
|
versionInfo2Res: VersionInfo2Response;
|
||||||
loginSession: LoginSession;
|
loginSession: LoginSession;
|
||||||
loginRes: LoginResponse;
|
loginRes: LoginResponse;
|
||||||
|
user: User;
|
||||||
|
authRes: AuthResponse;
|
||||||
|
|
||||||
currentRoomInfo: RoomInfo;
|
currentRoomInfo: RoomInfo;
|
||||||
|
|
||||||
|
@ -91,8 +124,9 @@ export class FormSectionComponent implements OnInit, OnDestroy {
|
||||||
selectedSticker: StickerFilesInfo;
|
selectedSticker: StickerFilesInfo;
|
||||||
|
|
||||||
/** About Translation */
|
/** About Translation */
|
||||||
translationSimpleview = false;
|
isTranslationProcess = false;
|
||||||
translationPreview = false;
|
translationSimpleview = true;
|
||||||
|
translationPreview = true;
|
||||||
destLocale = 'en'; // default English :: en
|
destLocale = 'en'; // default English :: en
|
||||||
translationPreviewInfo: {
|
translationPreviewInfo: {
|
||||||
previewInfo: TranslationSaveResponse | null;
|
previewInfo: TranslationSaveResponse | null;
|
||||||
|
@ -108,14 +142,13 @@ export class FormSectionComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
SelectorType = SelectorType;
|
SelectorType = SelectorType;
|
||||||
|
|
||||||
private ngOnDestroySubject: Subject<boolean>;
|
|
||||||
constructor(
|
constructor(
|
||||||
|
private piService: PiService,
|
||||||
private appFileService: AppFileService,
|
private appFileService: AppFileService,
|
||||||
private appChatService: AppChatService,
|
private appChatService: AppChatService,
|
||||||
private store: Store<any>,
|
private store: Store<any>,
|
||||||
private i18nService: I18nService,
|
private i18nService: I18nService,
|
||||||
private dialog: MatDialog,
|
private dialog: MatDialog,
|
||||||
private localStorageService: LocalStorageService,
|
|
||||||
private logService: LogService,
|
private logService: LogService,
|
||||||
private appAuthenticationService: AppAuthenticationService,
|
private appAuthenticationService: AppAuthenticationService,
|
||||||
private commonApiService: CommonApiService,
|
private commonApiService: CommonApiService,
|
||||||
|
@ -123,8 +156,6 @@ export class FormSectionComponent implements OnInit, OnDestroy {
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.ngOnDestroySubject = new Subject<boolean>();
|
|
||||||
|
|
||||||
this.store
|
this.store
|
||||||
.pipe(
|
.pipe(
|
||||||
takeUntil(this.ngOnDestroySubject),
|
takeUntil(this.ngOnDestroySubject),
|
||||||
|
@ -133,56 +164,83 @@ export class FormSectionComponent implements OnInit, OnDestroy {
|
||||||
.subscribe((versionInfo2Res) => {
|
.subscribe((versionInfo2Res) => {
|
||||||
this.versionInfo2Res = versionInfo2Res;
|
this.versionInfo2Res = versionInfo2Res;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.store
|
||||||
|
.pipe(takeUntil(this.ngOnDestroySubject), select(UserSelector.user))
|
||||||
|
.subscribe((user) => {
|
||||||
|
this.user = user;
|
||||||
|
});
|
||||||
|
|
||||||
this.store
|
this.store
|
||||||
.pipe(takeUntil(this.ngOnDestroySubject), select(LoginSelector.loginRes))
|
.pipe(takeUntil(this.ngOnDestroySubject), select(LoginSelector.loginRes))
|
||||||
.subscribe((loginRes) => {
|
.subscribe((loginRes) => {
|
||||||
this.loginRes = loginRes;
|
this.loginRes = loginRes;
|
||||||
});
|
});
|
||||||
this.appAuthenticationService
|
|
||||||
.getLoginSession$()
|
|
||||||
.pipe(takeUntil(this.ngOnDestroySubject))
|
|
||||||
.subscribe((loginSession) => (this.loginSession = loginSession));
|
|
||||||
|
|
||||||
this.store
|
this.store
|
||||||
.pipe(
|
.pipe(
|
||||||
takeUntil(this.ngOnDestroySubject),
|
takeUntil(this.ngOnDestroySubject),
|
||||||
select(
|
select(AuthorizationSelector.authResponse)
|
||||||
(state: any) => state.chat.room.rooms.entities as Dictionary<RoomInfo>
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
.subscribe((rooms) => {
|
.subscribe((authRes) => {
|
||||||
if (!!this.roomId) {
|
this.authRes = authRes;
|
||||||
this.currentRoomInfo = rooms[this.roomId];
|
|
||||||
|
|
||||||
this.changeDetectorRef.detectChanges();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
if (!!this.ngOnDestroySubject) {
|
if (!!this.ngOnDestroySubject) {
|
||||||
|
this.ngOnDestroySubject.next();
|
||||||
this.ngOnDestroySubject.complete();
|
this.ngOnDestroySubject.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!!this.roomIdSubject) {
|
||||||
|
this.roomIdSubject.next();
|
||||||
|
this.roomIdSubject.complete();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initializeRoomData() {
|
||||||
|
if (!!this.messageInput) {
|
||||||
|
this.messageInput.nativeElement.value = '';
|
||||||
|
}
|
||||||
|
this.selectorType = SelectorType.EMPTY;
|
||||||
|
this.translationSimpleview = false;
|
||||||
|
this.changeTranslationSimpleview.emit(false);
|
||||||
|
this.translationPreview = true;
|
||||||
|
this.destLocale = 'en'; // default English :: en
|
||||||
|
this.translationPreviewInfo = null;
|
||||||
|
|
||||||
|
this.store
|
||||||
|
.pipe(
|
||||||
|
takeUntil(merge(this.ngOnDestroySubject, this.roomIdSubject)),
|
||||||
|
select(RoomSelector.room, this.roomId)
|
||||||
|
)
|
||||||
|
.subscribe((room) => {
|
||||||
|
this.currentRoomInfo = room;
|
||||||
|
this.changeDetectorRef.markForCheck();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.loginSession = this.appAuthenticationService.getLoginSession();
|
||||||
|
}
|
||||||
/** About Selector */
|
/** About Selector */
|
||||||
onOpenSelector(type: SelectorType): void {
|
onOpenSelector(type: SelectorType): void {
|
||||||
this.selectorType = type;
|
this.selectorType = type;
|
||||||
this.changeDetectorRef.detectChanges();
|
this.changeDetectorRef.markForCheck();
|
||||||
}
|
}
|
||||||
clearSelector(): void {
|
clearSelector(): void {
|
||||||
this.selectorType = SelectorType.EMPTY;
|
this.selectorType = SelectorType.EMPTY;
|
||||||
this.selectedSticker = null;
|
this.selectedSticker = null;
|
||||||
this.changeDetectorRef.detectChanges();
|
this.changeDetectorRef.markForCheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Element Handling */
|
/** Element Handling */
|
||||||
focus(clearField: boolean = true): void {
|
focus(clearField: boolean = true): void {
|
||||||
if (!!this.messageInput) {
|
if (!!this.messageInput) {
|
||||||
if (!!clearField) {
|
if (!!clearField) {
|
||||||
|
if (this.selectorType !== SelectorType.TRANSLATION) {
|
||||||
|
this.clearSelector();
|
||||||
|
}
|
||||||
this.messageInput.nativeElement.value = '';
|
this.messageInput.nativeElement.value = '';
|
||||||
|
|
||||||
this.clearSelector();
|
|
||||||
}
|
}
|
||||||
this.messageInput.nativeElement.focus();
|
this.messageInput.nativeElement.focus();
|
||||||
}
|
}
|
||||||
|
@ -201,6 +259,7 @@ export class FormSectionComponent implements OnInit, OnDestroy {
|
||||||
} else {
|
} else {
|
||||||
// selector open
|
// selector open
|
||||||
self.onOpenSelector(SelectorType.FILEUPLOAD);
|
self.onOpenSelector(SelectorType.FILEUPLOAD);
|
||||||
|
self.changeDetectorRef.detectChanges();
|
||||||
|
|
||||||
// FileuploadItem Init. & FileSelector Init.
|
// FileuploadItem Init. & FileSelector Init.
|
||||||
const fileUploadItems = FileUploadItem.fromFiles(fileList);
|
const fileUploadItems = FileUploadItem.fromFiles(fileList);
|
||||||
|
@ -213,6 +272,7 @@ export class FormSectionComponent implements OnInit, OnDestroy {
|
||||||
self.appChatService
|
self.appChatService
|
||||||
.sendMessageOfAttachFile(
|
.sendMessageOfAttachFile(
|
||||||
self.loginRes,
|
self.loginRes,
|
||||||
|
self.user,
|
||||||
self.loginSession.deviceType,
|
self.loginSession.deviceType,
|
||||||
self.currentRoomInfo.roomId,
|
self.currentRoomInfo.roomId,
|
||||||
fileUploadItems
|
fileUploadItems
|
||||||
|
@ -226,10 +286,13 @@ export class FormSectionComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
alert(err);
|
self.clearSelector();
|
||||||
if (!!self.fileUploadSelector) {
|
if (!!self.fileUploadSelector) {
|
||||||
self.fileUploadSelector.onUploadComplete();
|
self.fileUploadSelector.onUploadComplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const msg = this.i18nService.t('common:file.errors.failToUpload');
|
||||||
|
alert(msg);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -240,13 +303,16 @@ export class FormSectionComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
onKeydown(event: KeyboardEvent) {
|
onKeydown(event: KeyboardEvent) {
|
||||||
if (event.key === 'PageUp' || event.key === 'PageDown') {
|
// if (event.key === 'PageUp' || event.key === 'PageDown') {
|
||||||
event.preventDefault();
|
// event.preventDefault();
|
||||||
return false;
|
// return false;
|
||||||
} else if (event.key === 'Enter' && !event.shiftKey) {
|
// } else if (event.key === 'Enter' && !event.shiftKey) {
|
||||||
event.preventDefault();
|
// event.preventDefault();
|
||||||
this.send();
|
// this.send();
|
||||||
}
|
// }
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
this.send();
|
||||||
}
|
}
|
||||||
|
|
||||||
onSelectedSticker(stickerInfo: StickerFilesInfo) {
|
onSelectedSticker(stickerInfo: StickerFilesInfo) {
|
||||||
|
@ -254,9 +320,37 @@ export class FormSectionComponent implements OnInit, OnDestroy {
|
||||||
this.focus(false);
|
this.focus(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onPasteReply(event: ClipboardEvent) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
// this.platform_readFromClipboard().then(async (data) => {
|
||||||
|
// console.log(data);
|
||||||
|
// console.log(data.html);
|
||||||
|
// console.log(data.image);
|
||||||
|
// console.log(data.imageDataUrl);
|
||||||
|
// console.log(data.text);
|
||||||
|
|
||||||
|
// console.log(JSON.stringify(event.clipboardData.items));
|
||||||
|
// if ((!!data.image && !!data.text) || !!data.image) {
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// for (const item of items) {
|
||||||
|
// if (item.type.indexOf('image') === 0) {
|
||||||
|
// blob = item.getAsFile();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// console.log(JSON.stringify(event.clipboardData.items));
|
||||||
|
// this.nativeService.platform_readFromClipboard().then(async (data) => {
|
||||||
|
// console.log(data);
|
||||||
|
// console.log(JSON.stringify(event.clipboardData.items));
|
||||||
|
// if ((!!data.image && !!data.text) || !!data.image) {
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
}
|
||||||
async send() {
|
async send() {
|
||||||
const roomId = this.currentRoomInfo.roomId;
|
const roomId = this.currentRoomInfo.roomId;
|
||||||
const userSeq = this.loginRes.userSeq;
|
const userSeq = String(this.user.info.seq);
|
||||||
let message = this.messageInput.nativeElement.value;
|
let message = this.messageInput.nativeElement.value;
|
||||||
|
|
||||||
if (!!message || message.trim().length > 0) {
|
if (!!message || message.trim().length > 0) {
|
||||||
|
@ -272,11 +366,11 @@ export class FormSectionComponent implements OnInit, OnDestroy {
|
||||||
AlertDialogData,
|
AlertDialogData,
|
||||||
AlertDialogResult
|
AlertDialogResult
|
||||||
>(AlertDialogComponent, {
|
>(AlertDialogComponent, {
|
||||||
|
panelClass: 'min-create-dialog',
|
||||||
data: {
|
data: {
|
||||||
title: this.i18nService.t('errors.label'),
|
title: this.i18nService.t('chat:errors.label'),
|
||||||
message: this.i18nService.t('errors.inputChatMessage')
|
message: this.i18nService.t('chat:errors.inputChatMessage')
|
||||||
},
|
}
|
||||||
panelClass: ''
|
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -301,14 +395,7 @@ export class FormSectionComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
this.clearSelector();
|
this.clearSelector();
|
||||||
} else {
|
} else {
|
||||||
this.appChatService.sendMessageOfTranslate(
|
this.sendMessageOfTranslate(message);
|
||||||
this.loginRes,
|
|
||||||
this.loginSession.deviceType,
|
|
||||||
this.destLocale,
|
|
||||||
roomId,
|
|
||||||
message,
|
|
||||||
this.selectedSticker
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else if (!!this.selectedSticker) {
|
} else if (!!this.selectedSticker) {
|
||||||
/** CASE : Sticker */
|
/** CASE : Sticker */
|
||||||
|
@ -326,6 +413,7 @@ export class FormSectionComponent implements OnInit, OnDestroy {
|
||||||
/** CASE : MASS TEXT */
|
/** CASE : MASS TEXT */
|
||||||
this.appChatService.sendMessageOfMassText(
|
this.appChatService.sendMessageOfMassText(
|
||||||
this.loginRes,
|
this.loginRes,
|
||||||
|
this.user,
|
||||||
this.loginSession.deviceType,
|
this.loginSession.deviceType,
|
||||||
roomId,
|
roomId,
|
||||||
message
|
message
|
||||||
|
@ -335,6 +423,205 @@ export class FormSectionComponent implements OnInit, OnDestroy {
|
||||||
this.appChatService.sendMessageOfNormal(userSeq, roomId, message);
|
this.appChatService.sendMessageOfNormal(userSeq, roomId, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.eventSendTrigger.emit(0);
|
||||||
this.focus();
|
this.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sendMessageOfTranslate(message: string) {
|
||||||
|
if (!!this.isTranslationProcess) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isTranslationProcess = true;
|
||||||
|
|
||||||
|
this.commonApiService
|
||||||
|
.translationSave({
|
||||||
|
userSeq: String(this.user.info.seq),
|
||||||
|
token: this.loginRes.tokenString,
|
||||||
|
deviceType: this.loginSession.deviceType,
|
||||||
|
original: message,
|
||||||
|
roomId: this.roomId,
|
||||||
|
srcLocale: '',
|
||||||
|
destLocale: this.destLocale
|
||||||
|
} as TranslationSaveRequest)
|
||||||
|
.pipe(
|
||||||
|
take(1),
|
||||||
|
map((res) => {
|
||||||
|
if (res.statusCode === StatusCode.Success) {
|
||||||
|
let sentMessage = '';
|
||||||
|
let eventType = EventType.Translation;
|
||||||
|
let previewObject: TranslationEventJson | MassTranslationEventJson;
|
||||||
|
if (res.translationSeq > 0) {
|
||||||
|
// Mass Text Translation
|
||||||
|
previewObject = res;
|
||||||
|
sentMessage = res.returnJson;
|
||||||
|
eventType = EventType.MassTranslation;
|
||||||
|
} else {
|
||||||
|
// Normal Text Translation
|
||||||
|
previewObject = {
|
||||||
|
locale: this.destLocale,
|
||||||
|
original: message,
|
||||||
|
translation: res.translation,
|
||||||
|
stickername: '',
|
||||||
|
stickerfile: !!this.selectedSticker
|
||||||
|
? this.selectedSticker.index
|
||||||
|
: ''
|
||||||
|
};
|
||||||
|
sentMessage = JSON.stringify(previewObject);
|
||||||
|
eventType = EventType.Translation;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!!this.translationPreview) {
|
||||||
|
this.translationPreviewInfo = {
|
||||||
|
previewInfo: res,
|
||||||
|
translationType: eventType
|
||||||
|
};
|
||||||
|
this.changeDetectorRef.markForCheck();
|
||||||
|
} else {
|
||||||
|
this._sendTranslationMessage(sentMessage, eventType);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// error
|
||||||
|
this._translationError();
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
catchError((error) => {
|
||||||
|
this._translationError();
|
||||||
|
return of(this.logService.error('error', error));
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.subscribe(() => {
|
||||||
|
this.isTranslationProcess = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangeTranslationSimpleView(value: boolean) {
|
||||||
|
this.translationSimpleview = value;
|
||||||
|
this.changeTranslationSimpleview.emit(value);
|
||||||
|
}
|
||||||
|
onChangeTranslationPreView(value: boolean) {
|
||||||
|
this.translationPreview = value;
|
||||||
|
}
|
||||||
|
onChangeDestLocale(destLocale: string) {
|
||||||
|
this.destLocale = destLocale;
|
||||||
|
}
|
||||||
|
onSendTranslationMessage(params: {
|
||||||
|
previewInfo: TranslationSaveResponse | null;
|
||||||
|
translationType: EventType.Translation | EventType.MassTranslation;
|
||||||
|
}) {
|
||||||
|
let sentMessage = '';
|
||||||
|
if (params.translationType === EventType.MassTranslation) {
|
||||||
|
// Mass Text Translation
|
||||||
|
sentMessage = params.previewInfo.returnJson;
|
||||||
|
} else {
|
||||||
|
sentMessage = JSON.stringify({
|
||||||
|
locale: params.previewInfo.destLocale,
|
||||||
|
original: params.previewInfo.original,
|
||||||
|
translation: params.previewInfo.translation,
|
||||||
|
stickername: '',
|
||||||
|
stickerfile: !!this.selectedSticker ? this.selectedSticker.index : ''
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this._sendTranslationMessage(sentMessage, params.translationType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _translationError() {
|
||||||
|
this.isTranslationProcess = false;
|
||||||
|
this.dialog.open<AlertDialogComponent, AlertDialogData, AlertDialogResult>(
|
||||||
|
AlertDialogComponent,
|
||||||
|
{
|
||||||
|
data: {
|
||||||
|
title: this.i18nService.t('chat:errors.label'),
|
||||||
|
message: this.i18nService.t('chat:errors.translateServerError')
|
||||||
|
},
|
||||||
|
panelClass: 'min-create-dialog'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
private _sendTranslationMessage(sentMessage: string, eventType: EventType) {
|
||||||
|
this.appChatService.sendMessageOfTranslate(
|
||||||
|
String(this.user.info.seq),
|
||||||
|
this.roomId,
|
||||||
|
eventType,
|
||||||
|
sentMessage
|
||||||
|
);
|
||||||
|
this.translationPreviewInfo = undefined;
|
||||||
|
this.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
onSendEventEmail(type: SendEventMailType): void {
|
||||||
|
this.store
|
||||||
|
.pipe(take(1), select(ChattingSelector.eventList, this._roomId))
|
||||||
|
.subscribe((eventList) => {
|
||||||
|
if (!!eventList && eventList.length > 0) {
|
||||||
|
const self = this;
|
||||||
|
const dialogRef = this.dialog.open<
|
||||||
|
ConfirmDialogComponent,
|
||||||
|
ConfirmDialogData,
|
||||||
|
ConfirmDialogResult
|
||||||
|
>(ConfirmDialogComponent, {
|
||||||
|
panelClass: 'min-create-dialog',
|
||||||
|
data: {
|
||||||
|
title: this.i18nService.t('chat:label.emailSend'),
|
||||||
|
html: this.i18nService.t(
|
||||||
|
type === SendEventMailType.ALL
|
||||||
|
? 'chat:dialog.confirmSendEventEmailAll'
|
||||||
|
: 'chat:dialog.confirmSendEventEmailMe'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
dialogRef
|
||||||
|
.afterClosed()
|
||||||
|
.pipe(take(1))
|
||||||
|
.subscribe((result) => {
|
||||||
|
if (!!result && !!result.choice) {
|
||||||
|
const req: SendEventEmailRequest = {
|
||||||
|
userSeq: String(this.user.info.seq),
|
||||||
|
deviceType: this.loginSession.deviceType,
|
||||||
|
tokenKey: this.loginRes.tokenString,
|
||||||
|
roomSeq: this._roomId,
|
||||||
|
eventSeq: String(eventList[0].seq),
|
||||||
|
sendType: type
|
||||||
|
};
|
||||||
|
this.piService
|
||||||
|
.sendEventEmail(req)
|
||||||
|
.pipe(take(1))
|
||||||
|
.subscribe(
|
||||||
|
(res: SendEventEmailResponse) => {
|
||||||
|
if (res.intStatusCode === PiStatusCode.Success) {
|
||||||
|
this.dialog.open<
|
||||||
|
AlertDialogComponent,
|
||||||
|
AlertDialogData,
|
||||||
|
AlertDialogResult
|
||||||
|
>(AlertDialogComponent, {
|
||||||
|
panelClass: 'min-create-dialog',
|
||||||
|
data: {
|
||||||
|
title: this.i18nService.t('chat:label.emailSend'),
|
||||||
|
message: this.i18nService.t(
|
||||||
|
'chat:dialog.sendEventEmailSuccess'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
self.selectorType = SelectorType.EMPTY;
|
||||||
|
} else {
|
||||||
|
this.logService.error(res.strErrorMessage);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
this.logService.error(error);
|
||||||
|
},
|
||||||
|
() => {}
|
||||||
|
);
|
||||||
|
|
||||||
|
this.logService.debug(
|
||||||
|
this.i18nService.t('chat:dialog.sendEventEmailSuccess')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,74 +1,163 @@
|
||||||
<mat-toolbar class="info-chat-toolbar">
|
<mat-toolbar class="info-chat-toolbar">
|
||||||
<mat-toolbar-row>
|
<mat-toolbar-row class="info-chat-toolbar-content">
|
||||||
<div class="profileImage">
|
<div class="chat-room-profile">
|
||||||
<img
|
<div class="profile-image">
|
||||||
class="thumbnail"
|
<img
|
||||||
ucapImage
|
class="thumbnail"
|
||||||
[base]="versionInfo2Res?.profileRoot"
|
ucapImage
|
||||||
[path]="roomImage"
|
[base]="versionInfo2Res?.profileRoot"
|
||||||
[default]="defaultProfileImage"
|
[path]="roomImage"
|
||||||
/>
|
[default]="
|
||||||
|
currentRoomInfo?.roomType === RoomType.Multi
|
||||||
|
? defaultProfileImageMulti
|
||||||
|
: defaultProfileImage
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span class="chat-room-subject"
|
||||||
>{{ roomName }}
|
><mat-icon
|
||||||
<span
|
*ngIf="!!currentRoomInfo?.isTimeRoom"
|
||||||
class="user-count"
|
class="ico-timer-unit material-icons-outlined"
|
||||||
|
>timer</mat-icon
|
||||||
|
><span>{{ roomName }}</span>
|
||||||
|
<strong
|
||||||
|
class="user-count text-accent-color"
|
||||||
*ngIf="currentRoomInfo?.roomType === RoomType.Multi"
|
*ngIf="currentRoomInfo?.roomType === RoomType.Multi"
|
||||||
>
|
>
|
||||||
(<strong>{{ currentRoomInfo?.joinUserCount }}</strong
|
{{ currentRoomInfo?.joinUserCount }}
|
||||||
>)
|
</strong>
|
||||||
</span>
|
|
||||||
</span>
|
</span>
|
||||||
<span class="example-spacer"></span>
|
<span class="example-spacer"></span>
|
||||||
<div>
|
<div class="btn-chat-room-top">
|
||||||
<button
|
<button
|
||||||
mat-mini-fab
|
mat-icon-button
|
||||||
color="primary"
|
color="primary"
|
||||||
aria-label="search"
|
aria-label="search"
|
||||||
matTooltip="{{ 'label.search' | ucapI18n }}"
|
matTooltip="{{ 'chat:label.search' | ucapI18n }}"
|
||||||
(click)="onOpenChatSearch()"
|
(click)="onOpenChatSearch()"
|
||||||
>
|
>
|
||||||
<mat-icon>search</mat-icon>
|
<mat-icon>search</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
mat-mini-fab
|
mat-icon-button
|
||||||
color="primary"
|
color="primary"
|
||||||
aria-label="alarm"
|
aria-label="alarm"
|
||||||
matTooltip="{{
|
matTooltip="{{
|
||||||
(currentRoomInfo?.receiveAlarm
|
(currentRoomInfo?.receiveAlarm
|
||||||
? 'label.notificationIsOn'
|
? 'chat:label.turnOnRoomAlert'
|
||||||
: 'label.notificationIsOff'
|
: 'chat:label.turnOffRoomAlert'
|
||||||
) | ucapI18n
|
) | ucapI18n
|
||||||
}}"
|
}}"
|
||||||
(click)="onToggleAlarm(currentRoomInfo)"
|
(click)="onToggleAlarm(currentRoomInfo)"
|
||||||
>
|
>
|
||||||
<mat-icon *ngIf="currentRoomInfo?.receiveAlarm">notifications</mat-icon>
|
<mat-icon
|
||||||
|
*ngIf="currentRoomInfo?.receiveAlarm"
|
||||||
|
class="material-icons-outlined"
|
||||||
|
>notifications</mat-icon
|
||||||
|
>
|
||||||
|
|
||||||
<mat-icon *ngIf="!currentRoomInfo?.receiveAlarm"
|
<mat-icon
|
||||||
|
*ngIf="!currentRoomInfo?.receiveAlarm"
|
||||||
|
class="material-icons-outlined"
|
||||||
>notifications_off</mat-icon
|
>notifications_off</mat-icon
|
||||||
>
|
>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<!-- <button
|
||||||
mat-mini-fab
|
mat-icon-button
|
||||||
|
class="btn-icon-favorite"
|
||||||
color="primary"
|
color="primary"
|
||||||
aria-label="show room users"
|
aria-label="show room users"
|
||||||
matTooltip="{{ 'label.showRoomUsers' | ucapI18n }}"
|
matTooltip="{{ 'chat:label.favorite' | ucapI18n }}"
|
||||||
(click)="onOpenRoomUserList(currentRoomInfo)"
|
|
||||||
>
|
|
||||||
<mat-icon>group</mat-icon>
|
|
||||||
</button>
|
|
||||||
<button mat-mini-fab color="primary" aria-label="">
|
|
||||||
<mat-icon>more_vert</mat-icon>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
mat-mini-fab
|
|
||||||
color="primary"
|
|
||||||
aria-label="Menu"
|
|
||||||
matTooltip="{{ 'label.menu' | ucapI18n }}"
|
|
||||||
(click)="onRightDrawerToggle()"
|
(click)="onRightDrawerToggle()"
|
||||||
>
|
>
|
||||||
<mat-icon>menu</mat-icon>
|
<mat-icon>star_outline</mat-icon>
|
||||||
|
</button> -->
|
||||||
|
<button
|
||||||
|
mat-icon-button
|
||||||
|
color="primary"
|
||||||
|
aria-label=""
|
||||||
|
[matMenuTriggerFor]="chatRoomMenu"
|
||||||
|
matTooltip="{{ 'chat:label.menu' | ucapI18n }}"
|
||||||
|
>
|
||||||
|
<mat-icon>more_horiz</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</mat-toolbar-row>
|
</mat-toolbar-row>
|
||||||
</mat-toolbar>
|
</mat-toolbar>
|
||||||
|
|
||||||
|
<mat-menu #chatRoomMenu="matMenu" class="chat-menu-box">
|
||||||
|
<div class="menu-title" (click)="$event.stopPropagation()">
|
||||||
|
{{ roomName }}
|
||||||
|
</div>
|
||||||
|
<mat-divider></mat-divider>
|
||||||
|
<div class="chat-menu-box-body">
|
||||||
|
<div class="data">
|
||||||
|
<div class="sub-title" (click)="$event.stopPropagation()">
|
||||||
|
<mat-icon class="material-icons-outlined">inbox</mat-icon
|
||||||
|
><span>{{ 'chat:label.data' | ucapI18n }}</span>
|
||||||
|
<!--<mat-slide-toggle labelPosition="before" class="simpleview">
|
||||||
|
</mat-slide-toggle>-->
|
||||||
|
</div>
|
||||||
|
<div class="btn">
|
||||||
|
<button mat-button (click)="onClickRoomMenu('ATTACH_IMAGE')">
|
||||||
|
{{ 'chat:label.image' | ucapI18n }}
|
||||||
|
</button>
|
||||||
|
<button mat-button (click)="onClickRoomMenu('ATTACH_VIDEO')">
|
||||||
|
{{ 'chat:label.video' | ucapI18n }}
|
||||||
|
</button>
|
||||||
|
<button mat-button (click)="onClickRoomMenu('ATTACH_FILE')">
|
||||||
|
{{ 'chat:label.attachFile' | ucapI18n }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- <button
|
||||||
|
mat-menu-item
|
||||||
|
*ngIf="getShowContextMenu('EVENT')"
|
||||||
|
(click)="onClickRoomMenu('EVENT')"
|
||||||
|
>
|
||||||
|
<mat-icon class="material-icons-outlined">calendar_today</mat-icon
|
||||||
|
>{{ 'chat:label.event' | ucapI18n }}
|
||||||
|
</button> -->
|
||||||
|
<button
|
||||||
|
mat-menu-item
|
||||||
|
*ngIf="getShowContextMenu('ROOM_USERS')"
|
||||||
|
(click)="onClickRoomMenu('ROOM_USERS')"
|
||||||
|
>
|
||||||
|
<mat-icon>person_outline</mat-icon
|
||||||
|
>{{ 'chat:label.showRoomUsers' | ucapI18n }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
mat-menu-item
|
||||||
|
*ngIf="getShowContextMenu('CHANGE_ROOM_USERS')"
|
||||||
|
(click)="onClickRoomMenu('CHANGE_ROOM_USERS')"
|
||||||
|
>
|
||||||
|
<mat-icon class="material-icons-outlined">person_add</mat-icon
|
||||||
|
>{{ 'chat:label.addRoomUsers' | ucapI18n }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
mat-menu-item
|
||||||
|
*ngIf="getShowContextMenu('ADD_GROUP')"
|
||||||
|
(click)="onClickRoomMenu('ADD_GROUP')"
|
||||||
|
>
|
||||||
|
<mat-icon class="material-icons-outlined">group_add</mat-icon
|
||||||
|
>{{ 'chat:label.addGroup' | ucapI18n }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
mat-menu-item
|
||||||
|
*ngIf="getShowContextMenu('SETTING')"
|
||||||
|
(click)="onClickRoomMenu('SETTING')"
|
||||||
|
>
|
||||||
|
<mat-icon class="material-icons-outlined">settings</mat-icon
|
||||||
|
>{{ 'chat:label.roomSetting' | ucapI18n }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
mat-menu-item
|
||||||
|
class="btn-exit"
|
||||||
|
*ngIf="getShowContextMenu('EXIT')"
|
||||||
|
(click)="onClickRoomMenu('EXIT')"
|
||||||
|
>
|
||||||
|
{{ 'chat:label.exitFromRoom' | ucapI18n }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</mat-menu>
|
||||||
|
|
|
@ -4,12 +4,73 @@
|
||||||
height: 50px;
|
height: 50px;
|
||||||
min-height: 50px;
|
min-height: 50px;
|
||||||
background-color: $white;
|
background-color: $white;
|
||||||
display: flex;
|
.info-chat-toolbar-content {
|
||||||
flex-direction: row;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-content: center;
|
|
||||||
.mat-toolbar-row {
|
|
||||||
height: 50px;
|
height: 50px;
|
||||||
min-height: 50px;
|
min-height: 50px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-content: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
@include screen(xs) {
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
.chat-room-profile {
|
||||||
|
align-self: center;
|
||||||
|
margin-right: 15px;
|
||||||
|
height: 38px;
|
||||||
|
flex: 0 0 0;
|
||||||
|
@include profile-avatar-default(
|
||||||
|
0,
|
||||||
|
14,
|
||||||
|
$warm-pink,
|
||||||
|
18px
|
||||||
|
); //오른 아래 공간, 모바일 온라인 아이콘 크기, 모바일 아이콘 색, 모바일 아이콘 bg크기
|
||||||
|
.profile-image {
|
||||||
|
@include avatar-img(36px, 0); //아바타 크기, 왼쪽공간
|
||||||
|
background-color: #d1f6ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.chat-room-subject {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
color: $gray-re3;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
display: flex !important;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
@include ellipsis-column(1);
|
||||||
|
.ico-timer-unit {
|
||||||
|
max-width: 18px !important;
|
||||||
|
height: 18px !important;
|
||||||
|
line-height: 18px;
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-right: 6px;
|
||||||
|
flex: 0 0 24px;
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
flex: 0 1 auto;
|
||||||
|
@include ellipsis(1);
|
||||||
|
//width: ;
|
||||||
|
}
|
||||||
|
strong {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
padding-left: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.btn-chat-room-top {
|
||||||
|
flex: 1 0 160px;
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: inline-flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
//대화방 즐겨찾기 - 개발보류
|
||||||
|
.btn-icon-favorite {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
import { combineLatest, Subject, merge } from 'rxjs';
|
||||||
|
import { takeUntil } from 'rxjs/operators';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Component,
|
Component,
|
||||||
OnInit,
|
OnInit,
|
||||||
|
@ -8,22 +11,26 @@ import {
|
||||||
EventEmitter,
|
EventEmitter,
|
||||||
ChangeDetectorRef
|
ChangeDetectorRef
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { Dictionary } from '@ngrx/entity';
|
|
||||||
import { Store, select } from '@ngrx/store';
|
|
||||||
import { combineLatest, Subject } from 'rxjs';
|
|
||||||
import { takeUntil } from 'rxjs/operators';
|
|
||||||
|
|
||||||
import { RoomSelector, RoomActions } from '@ucap/ng-store-chat';
|
import { Store, select } from '@ngrx/store';
|
||||||
import {
|
import { Dictionary } from '@ngrx/entity';
|
||||||
LoginSelector,
|
|
||||||
ConfigurationSelector
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
} from '@ucap/ng-store-authentication';
|
|
||||||
|
import { LocaleCode } from '@ucap/core';
|
||||||
|
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 { UserSelector } from '@ucap/ng-store-organization';
|
||||||
|
import { ConfigurationSelector } from '@ucap/ng-store-authentication';
|
||||||
import {
|
import {
|
||||||
|
RoomSelector,
|
||||||
|
RoomActions,
|
||||||
RoomUserMap,
|
RoomUserMap,
|
||||||
RoomUserShortMap
|
RoomUserShortMap
|
||||||
} from '@ucap/ng-store-chat/lib/store/room/state';
|
} from '@ucap/ng-store-chat';
|
||||||
import { LoginResponse } from '@ucap/protocol-authentication';
|
|
||||||
import { RoomInfo, RoomType, UpdateRequest } from '@ucap/protocol-room';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
TranslatePipe as OrganizationTranslate,
|
TranslatePipe as OrganizationTranslate,
|
||||||
|
@ -31,9 +38,8 @@ import {
|
||||||
} from '@ucap/ng-ui-organization';
|
} from '@ucap/ng-ui-organization';
|
||||||
|
|
||||||
import { AppChatService } from '@app/services/app-chat.service';
|
import { AppChatService } from '@app/services/app-chat.service';
|
||||||
import { I18nService } from '@ucap/ng-i18n';
|
import { ChatDrawType } from '@app/pages/chat/types/chat-draw.type';
|
||||||
import { VersionInfo2Response } from '@ucap/api-public';
|
import { DrawInfo } from '@app/pages/chat/models/draw-info';
|
||||||
import { LocaleCode } from '@ucap/core';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-sections-chat-info',
|
selector: 'app-sections-chat-info',
|
||||||
|
@ -42,10 +48,17 @@ import { LocaleCode } from '@ucap/core';
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class InfoSectionComponent implements OnInit, OnDestroy {
|
export class InfoSectionComponent implements OnInit, OnDestroy {
|
||||||
|
private roomIdSubject = new Subject<string>();
|
||||||
|
private ngOnDestroySubject: Subject<void> = new Subject();
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
set roomId(roomId: string) {
|
set roomId(roomId: string) {
|
||||||
this._roomId = roomId;
|
this._roomId = roomId;
|
||||||
|
|
||||||
|
this.roomIdSubject.next(roomId);
|
||||||
|
|
||||||
|
this.initializeRoomData();
|
||||||
|
|
||||||
// request selected room
|
// request selected room
|
||||||
if (!!this.roomId) {
|
if (!!this.roomId) {
|
||||||
this.store.dispatch(
|
this.store.dispatch(
|
||||||
|
@ -55,8 +68,6 @@ export class InfoSectionComponent implements OnInit, OnDestroy {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.getRoomInfo();
|
|
||||||
}
|
}
|
||||||
get roomId(): string {
|
get roomId(): string {
|
||||||
return this._roomId;
|
return this._roomId;
|
||||||
|
@ -68,31 +79,31 @@ export class InfoSectionComponent implements OnInit, OnDestroy {
|
||||||
openChatSearch = new EventEmitter<void>();
|
openChatSearch = new EventEmitter<void>();
|
||||||
|
|
||||||
@Output()
|
@Output()
|
||||||
rightDrawerToggle = new EventEmitter<void>();
|
rightDrawerToggle = new EventEmitter<DrawInfo>();
|
||||||
|
|
||||||
versionInfo2Res: VersionInfo2Response;
|
versionInfo2Res: VersionInfo2Response;
|
||||||
loginRes: LoginResponse;
|
user: User;
|
||||||
|
|
||||||
defaultProfileImage: string;
|
defaultProfileImage: string;
|
||||||
defaultProfileImageMulti: string;
|
defaultProfileImageMulti: string;
|
||||||
|
|
||||||
currentRoomInfo: RoomInfo;
|
currentRoomInfo: RoomInfo;
|
||||||
roomList: RoomInfo[];
|
roomList: RoomInfo[];
|
||||||
roomUsersDictionary: Dictionary<RoomUserMap>;
|
roomUsersMap: RoomUserMap;
|
||||||
roomUsersShortDictionary: Dictionary<RoomUserShortMap>;
|
roomUsersShortMap: RoomUserShortMap;
|
||||||
|
|
||||||
roomName: string;
|
roomName: string;
|
||||||
roomImage: string;
|
roomImage: string;
|
||||||
|
|
||||||
RoomType = RoomType;
|
RoomType = RoomType;
|
||||||
organizationTranslate: OrganizationTranslate;
|
organizationTranslate: OrganizationTranslate;
|
||||||
private ngOnDestroySubject: Subject<boolean>;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private store: Store<any>,
|
private store: Store<any>,
|
||||||
private appChatService: AppChatService,
|
private appChatService: AppChatService,
|
||||||
private i18nService: I18nService,
|
private i18nService: I18nService,
|
||||||
private translateService: TranslateService,
|
private translateService: TranslateService,
|
||||||
|
private dialog: MatDialog,
|
||||||
private changeDetectorRef: ChangeDetectorRef
|
private changeDetectorRef: ChangeDetectorRef
|
||||||
) {
|
) {
|
||||||
// language setting
|
// language setting
|
||||||
|
@ -105,12 +116,10 @@ export class InfoSectionComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
// default image setting
|
// default image setting
|
||||||
this.defaultProfileImage = this.appChatService.defaultProfileImage;
|
this.defaultProfileImage = this.appChatService.defaultProfileImage;
|
||||||
this.defaultProfileImageMulti = this.appChatService.defaultProfileImage;
|
this.defaultProfileImageMulti = this.appChatService.defaultProfileImageMulti;
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.ngOnDestroySubject = new Subject<boolean>();
|
|
||||||
|
|
||||||
this.store
|
this.store
|
||||||
.pipe(
|
.pipe(
|
||||||
takeUntil(this.ngOnDestroySubject),
|
takeUntil(this.ngOnDestroySubject),
|
||||||
|
@ -119,76 +128,58 @@ export class InfoSectionComponent implements OnInit, OnDestroy {
|
||||||
.subscribe((versionInfo2Res) => {
|
.subscribe((versionInfo2Res) => {
|
||||||
this.versionInfo2Res = versionInfo2Res;
|
this.versionInfo2Res = versionInfo2Res;
|
||||||
});
|
});
|
||||||
|
|
||||||
combineLatest([
|
|
||||||
this.store.pipe(select(LoginSelector.loginRes)),
|
|
||||||
this.store.pipe(select(RoomSelector.rooms)),
|
|
||||||
this.store.pipe(
|
|
||||||
select(
|
|
||||||
(state: any) =>
|
|
||||||
state.chat.room.roomUsers.entities as Dictionary<RoomUserMap>
|
|
||||||
)
|
|
||||||
),
|
|
||||||
this.store.pipe(
|
|
||||||
select(
|
|
||||||
(state: any) =>
|
|
||||||
state.chat.room.roomUsersShort.entities as Dictionary<
|
|
||||||
RoomUserShortMap
|
|
||||||
>
|
|
||||||
)
|
|
||||||
)
|
|
||||||
])
|
|
||||||
.pipe(takeUntil(this.ngOnDestroySubject))
|
|
||||||
.subscribe(([loginRes, rooms, roomUsers, roomUsersShort]) => {
|
|
||||||
this.loginRes = loginRes;
|
|
||||||
if (!!loginRes && !!this.roomId) {
|
|
||||||
this.roomList = rooms;
|
|
||||||
this.roomUsersDictionary = roomUsers;
|
|
||||||
this.roomUsersShortDictionary = roomUsersShort;
|
|
||||||
|
|
||||||
this.getRoomInfo();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
if (!!this.ngOnDestroySubject) {
|
if (!!this.ngOnDestroySubject) {
|
||||||
|
this.ngOnDestroySubject.next();
|
||||||
this.ngOnDestroySubject.complete();
|
this.ngOnDestroySubject.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!!this.roomIdSubject) {
|
||||||
|
this.roomIdSubject.next();
|
||||||
|
this.roomIdSubject.complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeRoomData() {
|
||||||
|
combineLatest([
|
||||||
|
this.store.pipe(select(UserSelector.user)),
|
||||||
|
this.store.pipe(select(RoomSelector.room, this.roomId)),
|
||||||
|
this.store.pipe(select(RoomSelector.roomUser, this.roomId)),
|
||||||
|
this.store.pipe(select(RoomSelector.roomUserShort, this.roomId))
|
||||||
|
])
|
||||||
|
.pipe(takeUntil(merge(this.ngOnDestroySubject, this.roomIdSubject)))
|
||||||
|
.subscribe(([user, room, roomUsers, roomUsersShort]) => {
|
||||||
|
this.user = user;
|
||||||
|
this.currentRoomInfo = room;
|
||||||
|
this.roomUsersMap = roomUsers;
|
||||||
|
this.roomUsersShortMap = roomUsersShort;
|
||||||
|
|
||||||
|
this.getRoomInfo();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getRoomInfo(): void {
|
getRoomInfo(): void {
|
||||||
// room render.
|
|
||||||
if (!this.roomList || this.roomList.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.roomName = '...';
|
this.roomName = '...';
|
||||||
const idx = this.roomList.findIndex(
|
|
||||||
(roomInfo) => roomInfo.roomId === this.roomId
|
|
||||||
);
|
|
||||||
if (idx > -1 && !!this.roomList && this.roomList.length > 0) {
|
|
||||||
this.currentRoomInfo = this.roomList[idx];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!!this.currentRoomInfo) {
|
if (!!this.currentRoomInfo) {
|
||||||
// Setting RoomName.
|
// Setting RoomName.
|
||||||
this.roomName = this.appChatService.getRoomName(
|
this.roomName = this.appChatService.getRoomName(
|
||||||
this.organizationTranslate,
|
this.organizationTranslate,
|
||||||
this.loginRes,
|
this.user,
|
||||||
this.currentRoomInfo,
|
this.currentRoomInfo,
|
||||||
this.roomUsersDictionary,
|
this.roomUsersMap,
|
||||||
this.roomUsersShortDictionary
|
this.roomUsersShortMap
|
||||||
);
|
);
|
||||||
|
|
||||||
this.roomImage = this.appChatService.getRoomProfileImage(
|
this.roomImage = this.appChatService.getRoomProfileImage(
|
||||||
|
this.user,
|
||||||
this.currentRoomInfo,
|
this.currentRoomInfo,
|
||||||
this.loginRes,
|
this.roomUsersMap,
|
||||||
this.roomUsersDictionary,
|
this.roomUsersShortMap
|
||||||
this.roomUsersShortDictionary
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
this.changeDetectorRef.detectChanges();
|
this.changeDetectorRef.markForCheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
onToggleAlarm(roomInfo: RoomInfo): void {
|
onToggleAlarm(roomInfo: RoomInfo): void {
|
||||||
|
@ -209,11 +200,9 @@ export class InfoSectionComponent implements OnInit, OnDestroy {
|
||||||
} as UpdateRequest
|
} as UpdateRequest
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
this.changeDetectorRef.detectChanges();
|
this.changeDetectorRef.markForCheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
onOpenRoomUserList(roomInfo: RoomInfo): void {}
|
|
||||||
|
|
||||||
onOpenChatSearch(): void {
|
onOpenChatSearch(): void {
|
||||||
this.openChatSearch.emit();
|
this.openChatSearch.emit();
|
||||||
}
|
}
|
||||||
|
@ -221,4 +210,64 @@ export class InfoSectionComponent implements OnInit, OnDestroy {
|
||||||
onRightDrawerToggle(): void {
|
onRightDrawerToggle(): void {
|
||||||
this.rightDrawerToggle.emit();
|
this.rightDrawerToggle.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onClickRoomMenu(type: string): void {
|
||||||
|
switch (type) {
|
||||||
|
case 'ATTACH_IMAGE':
|
||||||
|
this.rightDrawerToggle.emit({ chatDrawType: ChatDrawType.AttachImage });
|
||||||
|
break;
|
||||||
|
case 'ATTACH_VIDEO':
|
||||||
|
this.rightDrawerToggle.emit({ chatDrawType: ChatDrawType.AttachVideo });
|
||||||
|
break;
|
||||||
|
case 'ATTACH_FILE':
|
||||||
|
this.rightDrawerToggle.emit({ chatDrawType: ChatDrawType.AttachFile });
|
||||||
|
break;
|
||||||
|
case 'ADD_GROUP':
|
||||||
|
this.rightDrawerToggle.emit({ chatDrawType: ChatDrawType.AddGroup });
|
||||||
|
break;
|
||||||
|
case 'ROOM_USERS':
|
||||||
|
this.rightDrawerToggle.emit({ chatDrawType: ChatDrawType.RoomUsers });
|
||||||
|
break;
|
||||||
|
case 'CHANGE_ROOM_USERS':
|
||||||
|
this.rightDrawerToggle.emit({ chatDrawType: ChatDrawType.Invite });
|
||||||
|
break;
|
||||||
|
case 'SETTING':
|
||||||
|
this.rightDrawerToggle.emit({ chatDrawType: ChatDrawType.Setting });
|
||||||
|
break;
|
||||||
|
case 'EXIT':
|
||||||
|
this.appChatService.exitRoomDialog(this.currentRoomInfo);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getShowContextMenu(menuType: string) {
|
||||||
|
if (
|
||||||
|
['EVENT', 'ROOM_USERS', 'CHANGE_ROOM_USERS', 'ADD_GROUP', 'SETTING'].some(
|
||||||
|
(v) => v === menuType
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
!this.currentRoomInfo ||
|
||||||
|
!this.currentRoomInfo.roomType ||
|
||||||
|
[RoomType.Mytalk, RoomType.Allim, RoomType.Bot, RoomType.Link].some(
|
||||||
|
(v) => v === this.currentRoomInfo.roomType
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// else if (['CHAT_EXPORT'].some((v) => v === menuType)) {
|
||||||
|
// if (
|
||||||
|
// !this.currentRoomInfo ||
|
||||||
|
// !this.currentRoomInfo.roomType ||
|
||||||
|
// [RoomType.Allim, RoomType.Bot, RoomType.Link].some(
|
||||||
|
// (v) => v === this.currentRoomInfo.roomType
|
||||||
|
// )
|
||||||
|
// ) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,30 +1,12 @@
|
||||||
<div
|
<div fxFlexFill class="list-container">
|
||||||
*ngIf="!!searchObj && !searchObj.isShowSearch"
|
|
||||||
fxFlexFill
|
|
||||||
class="list-container"
|
|
||||||
>
|
|
||||||
<app-chat-room-expansion
|
<app-chat-room-expansion
|
||||||
|
[searchObj]="searchObj"
|
||||||
|
[currentRoomId]="currentRoomId"
|
||||||
[checkable]="checkable"
|
[checkable]="checkable"
|
||||||
[selectedRoomList]="selectedRoomList"
|
[selectedRoomList]="selectedRoomList"
|
||||||
(toggleItem)="onToggleItem($event)"
|
(toggleItem)="onToggleItem($event)"
|
||||||
(openChatRoom)="onOpenChatRoom($event)"
|
(openChatRoom)="onOpenChatRoom($event)"
|
||||||
|
(searchResultList)="onSearchResultList($event)"
|
||||||
>
|
>
|
||||||
</app-chat-room-expansion>
|
</app-chat-room-expansion>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="!!searchObj && searchObj.isShowSearch">
|
|
||||||
<ucap-chat-room-list-item-01
|
|
||||||
*ngFor="let roomInfo of searchRoomList"
|
|
||||||
[roomInfo]="roomInfo"
|
|
||||||
[roomName]="getRoomName(roomInfo)"
|
|
||||||
[profileImageRoot]="versionInfo2Res?.profileRoot"
|
|
||||||
[defaultProfileImage]="defaultProfileImage"
|
|
||||||
[profileImage]="getRoomProfileImage(roomInfo)"
|
|
||||||
[checked]="getChecked(roomInfo)"
|
|
||||||
[checkable]="checkable"
|
|
||||||
(toggleItem)="onToggleItem($event)"
|
|
||||||
(openChatRoom)="onOpenChatRoom($event)"
|
|
||||||
(toggleAlarm)="onToggleAlarm($event)"
|
|
||||||
(delRoom)="onDelRoom($event)"
|
|
||||||
(click)="onClickRoomItem($event, roomInfo)"
|
|
||||||
></ucap-chat-room-list-item-01>
|
|
||||||
</div>
|
|
||||||
|
|
|
@ -1,2 +1,4 @@
|
||||||
.list-container {
|
.list-container {
|
||||||
|
height: calc(100% - 90px) !important;
|
||||||
|
min-height: auto !important;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Subject, combineLatest } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
import { takeUntil, take } from 'rxjs/operators';
|
import { takeUntil } from 'rxjs/operators';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Component,
|
Component,
|
||||||
|
@ -9,91 +9,24 @@ import {
|
||||||
ChangeDetectorRef,
|
ChangeDetectorRef,
|
||||||
Input,
|
Input,
|
||||||
EventEmitter,
|
EventEmitter,
|
||||||
Output,
|
Output
|
||||||
NgZone
|
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
|
|
||||||
import { Store, select } from '@ngrx/store';
|
|
||||||
|
|
||||||
import {
|
|
||||||
FixedSizeVirtualScrollStrategy,
|
|
||||||
VIRTUAL_SCROLL_STRATEGY
|
|
||||||
} from '@angular/cdk/scrolling';
|
|
||||||
|
|
||||||
import { LoginResponse } from '@ucap/protocol-authentication';
|
|
||||||
|
|
||||||
import { LogService } from '@ucap/ng-logger';
|
import { LogService } from '@ucap/ng-logger';
|
||||||
import { SessionStorageService } from '@ucap/ng-web-storage';
|
import { RoomInfo } from '@ucap/protocol-room';
|
||||||
import {
|
import { Router, ActivatedRoute, Params } from '@angular/router';
|
||||||
LoginSelector,
|
import { QueryParams } from '@app/pages/chat/types/params.type';
|
||||||
ConfigurationSelector
|
import { SearchInfo } from '@app/pages/chat/models/search-info';
|
||||||
} from '@ucap/ng-store-authentication';
|
|
||||||
import { RoomSelector, RoomActions } from '@ucap/ng-store-chat';
|
|
||||||
import {
|
|
||||||
RoomInfo,
|
|
||||||
RoomType,
|
|
||||||
ExitAllRequest,
|
|
||||||
UpdateRequest,
|
|
||||||
ExitRequest
|
|
||||||
} from '@ucap/protocol-room';
|
|
||||||
import {
|
|
||||||
RoomUserMap,
|
|
||||||
RoomUserShortMap
|
|
||||||
} from '@ucap/ng-store-chat/lib/store/room/state';
|
|
||||||
import { Dictionary } from '@ngrx/entity';
|
|
||||||
import {
|
|
||||||
TranslatePipe as OrganizationTranslate,
|
|
||||||
TranslateService
|
|
||||||
} from '@ucap/ng-ui-organization';
|
|
||||||
import { I18nService } from '@ucap/ng-i18n';
|
|
||||||
import { AppChatService } from '@app/services/app-chat.service';
|
|
||||||
import {
|
|
||||||
DateService,
|
|
||||||
ConfirmDialogComponent,
|
|
||||||
ConfirmDialogData,
|
|
||||||
ConfirmDialogResult
|
|
||||||
} from '@ucap/ng-ui';
|
|
||||||
import { VersionInfo2Response } from '@ucap/api-public';
|
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
|
||||||
import { Router } from '@angular/router';
|
|
||||||
|
|
||||||
export class ChatVirtualScrollStrategy extends FixedSizeVirtualScrollStrategy {
|
|
||||||
constructor() {
|
|
||||||
super(60, 150, 200); // (itemSize, minBufferPx, maxBufferPx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-sections-chat-list',
|
selector: 'app-sections-chat-list',
|
||||||
templateUrl: './list.section.component.html',
|
templateUrl: './list.section.component.html',
|
||||||
styleUrls: ['./list.section.component.scss'],
|
styleUrls: ['./list.section.component.scss'],
|
||||||
providers: [
|
|
||||||
{
|
|
||||||
provide: VIRTUAL_SCROLL_STRATEGY,
|
|
||||||
useClass: ChatVirtualScrollStrategy
|
|
||||||
}
|
|
||||||
],
|
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class ListSectionComponent implements OnInit, OnDestroy {
|
export class ListSectionComponent implements OnInit, OnDestroy {
|
||||||
@Input()
|
@Input()
|
||||||
set searchObj(obj: { isShowSearch: boolean; searchWord: string }) {
|
searchObj: SearchInfo;
|
||||||
this._searchObj = obj;
|
|
||||||
|
|
||||||
if (obj.isShowSearch && obj.searchWord.localeCompare('') !== 0) {
|
|
||||||
this.onRoomSearch(obj);
|
|
||||||
} else {
|
|
||||||
this._searchObj.isShowSearch = false;
|
|
||||||
this.searchRoomList = [];
|
|
||||||
}
|
|
||||||
this.searchResultList.emit(this.searchRoomList);
|
|
||||||
}
|
|
||||||
|
|
||||||
get searchObj() {
|
|
||||||
return this._searchObj;
|
|
||||||
}
|
|
||||||
// tslint:disable-next-line: variable-name
|
|
||||||
_searchObj: any;
|
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
checkable = false;
|
checkable = false;
|
||||||
|
@ -110,277 +43,53 @@ export class ListSectionComponent implements OnInit, OnDestroy {
|
||||||
roomInfo: RoomInfo;
|
roomInfo: RoomInfo;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
@Output()
|
currentRoomId: string;
|
||||||
delRoom = new EventEmitter<RoomInfo>();
|
|
||||||
|
|
||||||
versionInfo2Res: VersionInfo2Response;
|
|
||||||
loginRes: LoginResponse;
|
|
||||||
|
|
||||||
defaultProfileImage: string;
|
|
||||||
defaultProfileImageMulti: string;
|
|
||||||
|
|
||||||
roomList: RoomInfo[];
|
roomList: RoomInfo[];
|
||||||
roomUsersDictionary: Dictionary<RoomUserMap>;
|
|
||||||
roomUsersShortDictionary: Dictionary<RoomUserShortMap>;
|
|
||||||
|
|
||||||
searchRoomList: RoomInfo[];
|
private ngOnDestroySubject: Subject<void> = new Subject();
|
||||||
|
|
||||||
roomGroup: { division: string; roomList: RoomInfo[] }[];
|
|
||||||
|
|
||||||
organizationTranslate: OrganizationTranslate;
|
|
||||||
|
|
||||||
private ngOnDestroySubject: Subject<boolean>;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private appChatService: AppChatService,
|
private activatedRoute: ActivatedRoute,
|
||||||
private dateService: DateService,
|
|
||||||
private sessionStorageService: SessionStorageService,
|
|
||||||
private i18nService: I18nService,
|
|
||||||
private translateService: TranslateService,
|
|
||||||
private store: Store<any>,
|
|
||||||
private dialog: MatDialog,
|
|
||||||
private changeDetectorRef: ChangeDetectorRef,
|
private changeDetectorRef: ChangeDetectorRef,
|
||||||
private ngZone: NgZone,
|
|
||||||
private logService: LogService
|
private logService: LogService
|
||||||
) {
|
) {}
|
||||||
// default image setting
|
|
||||||
this.defaultProfileImage = this.appChatService.defaultProfileImage;
|
|
||||||
this.defaultProfileImageMulti = this.appChatService.defaultProfileImage;
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.ngOnDestroySubject = new Subject<boolean>();
|
this.activatedRoute.queryParams
|
||||||
|
|
||||||
// language setting
|
|
||||||
this.translateService.setDefaultLang(this.i18nService.currentLng);
|
|
||||||
this.translateService.use(this.i18nService.currentLng);
|
|
||||||
this.organizationTranslate = new OrganizationTranslate(
|
|
||||||
this.translateService,
|
|
||||||
this.changeDetectorRef
|
|
||||||
);
|
|
||||||
this.i18nService.setDefaultNamespace('chat');
|
|
||||||
|
|
||||||
this.store
|
|
||||||
.pipe(
|
|
||||||
takeUntil(this.ngOnDestroySubject),
|
|
||||||
select(ConfigurationSelector.versionInfo2Response)
|
|
||||||
)
|
|
||||||
.subscribe((versionInfo2Res) => {
|
|
||||||
this.versionInfo2Res = versionInfo2Res;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.store
|
|
||||||
.pipe(takeUntil(this.ngOnDestroySubject), select(LoginSelector.loginRes))
|
|
||||||
.subscribe((loginRes) => {
|
|
||||||
this.loginRes = loginRes;
|
|
||||||
});
|
|
||||||
|
|
||||||
combineLatest([
|
|
||||||
this.store.pipe(select(RoomSelector.rooms)),
|
|
||||||
this.store.pipe(select(RoomSelector.standbyRooms))
|
|
||||||
])
|
|
||||||
.pipe(takeUntil(this.ngOnDestroySubject))
|
.pipe(takeUntil(this.ngOnDestroySubject))
|
||||||
.subscribe(([rooms, standbyRooms]) => {
|
.subscribe((params: Params) => {
|
||||||
rooms = (rooms || []).filter((info) => {
|
const seqParam = params[QueryParams.ROOM_ID];
|
||||||
return (
|
this.currentRoomId = !!seqParam ? seqParam : undefined;
|
||||||
info.isJoinRoom &&
|
|
||||||
!standbyRooms.find((standbyRoom) => standbyRoom === info.roomId)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
this.roomList = rooms;
|
|
||||||
|
|
||||||
this.changeDetectorRef.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
combineLatest([
|
|
||||||
this.store.pipe(
|
|
||||||
select(
|
|
||||||
(state: any) =>
|
|
||||||
state.chat.room.roomUsers.entities as Dictionary<RoomUserMap>
|
|
||||||
)
|
|
||||||
),
|
|
||||||
this.store.pipe(
|
|
||||||
select(
|
|
||||||
(state: any) =>
|
|
||||||
state.chat.room.roomUsersShort.entities as Dictionary<
|
|
||||||
RoomUserShortMap
|
|
||||||
>
|
|
||||||
)
|
|
||||||
)
|
|
||||||
])
|
|
||||||
.pipe(takeUntil(this.ngOnDestroySubject))
|
|
||||||
.subscribe(([roomUsers, roomUsersShort]) => {
|
|
||||||
this.roomUsersDictionary = roomUsers;
|
|
||||||
this.roomUsersShortDictionary = roomUsersShort;
|
|
||||||
this.changeDetectorRef.detectChanges();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
if (!!this.ngOnDestroySubject) {
|
if (!!this.ngOnDestroySubject) {
|
||||||
|
this.ngOnDestroySubject.next();
|
||||||
this.ngOnDestroySubject.complete();
|
this.ngOnDestroySubject.complete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getRoomName(roomInfo: RoomInfo): string {
|
|
||||||
if (!roomInfo) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
const roomName = this.appChatService.getRoomName(
|
|
||||||
this.organizationTranslate,
|
|
||||||
this.loginRes,
|
|
||||||
roomInfo,
|
|
||||||
this.roomUsersDictionary,
|
|
||||||
this.roomUsersShortDictionary
|
|
||||||
);
|
|
||||||
|
|
||||||
return roomName;
|
|
||||||
}
|
|
||||||
|
|
||||||
getRoomProfileImage(roomInfo: RoomInfo): string {
|
|
||||||
let roomImage = '';
|
|
||||||
if (!!roomInfo) {
|
|
||||||
roomImage = this.appChatService.getRoomProfileImage(
|
|
||||||
roomInfo,
|
|
||||||
this.loginRes,
|
|
||||||
this.roomUsersDictionary,
|
|
||||||
this.roomUsersShortDictionary
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return roomImage;
|
|
||||||
}
|
|
||||||
|
|
||||||
isToday(date: any) {
|
|
||||||
return this.dateService.isToday(date);
|
|
||||||
}
|
|
||||||
|
|
||||||
onRoomSearch(obj: { isShowSearch: boolean; searchWord: string }) {
|
|
||||||
const searchRoomList: RoomInfo[] = [];
|
|
||||||
|
|
||||||
this.roomList.forEach((roomInfo) => {
|
|
||||||
if (roomInfo.roomName.indexOf(obj.searchWord) > -1) {
|
|
||||||
searchRoomList.push(roomInfo);
|
|
||||||
} else {
|
|
||||||
const roomUsers = this.appChatService.getRoomUserList(
|
|
||||||
this.loginRes,
|
|
||||||
roomInfo.roomId,
|
|
||||||
this.roomUsersDictionary,
|
|
||||||
this.roomUsersShortDictionary
|
|
||||||
);
|
|
||||||
|
|
||||||
if (
|
|
||||||
roomUsers.existUsers &&
|
|
||||||
roomUsers.users.filter(
|
|
||||||
(userInfo) =>
|
|
||||||
userInfo.name.indexOf(obj.searchWord) > -1 ||
|
|
||||||
userInfo.nameEn.indexOf(obj.searchWord) > -1 ||
|
|
||||||
userInfo.nameCn.indexOf(obj.searchWord) > -1
|
|
||||||
).length > 0
|
|
||||||
) {
|
|
||||||
searchRoomList.push(roomInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.searchRoomList = searchRoomList;
|
|
||||||
}
|
|
||||||
|
|
||||||
getChecked(roomInfo: RoomInfo): boolean {
|
|
||||||
if (this.selectedRoomList.some((info) => info.roomId === roomInfo.roomId)) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onToggleItem(event: { checked: boolean; roomInfo: RoomInfo }): void {
|
onToggleItem(event: { checked: boolean; roomInfo: RoomInfo }): void {
|
||||||
this.toggleItem.emit(event);
|
this.toggleItem.emit(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
onClickRoomItem(event: MouseEvent, roomInfo: RoomInfo): void {
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
|
|
||||||
if (!!this.checkable) {
|
|
||||||
this.onToggleItem({
|
|
||||||
checked: !this.getChecked(roomInfo),
|
|
||||||
roomInfo
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.onOpenChatRoom(roomInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onOpenChatRoom(roomInfo: RoomInfo): void {
|
onOpenChatRoom(roomInfo: RoomInfo): void {
|
||||||
this.ngZone.run(() => {
|
this.router.navigate(
|
||||||
this.router.navigate(
|
[
|
||||||
[
|
'chat',
|
||||||
'chat',
|
|
||||||
{
|
|
||||||
outlets: { content: 'chatroom' }
|
|
||||||
}
|
|
||||||
],
|
|
||||||
{
|
{
|
||||||
queryParams: { roomId: roomInfo.roomId }
|
outlets: { content: 'chatroom' }
|
||||||
}
|
}
|
||||||
);
|
],
|
||||||
});
|
{
|
||||||
}
|
queryParams: { roomId: roomInfo.roomId }
|
||||||
|
|
||||||
onToggleAlarm(roomInfo: RoomInfo): void {
|
|
||||||
if (!roomInfo) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.store.dispatch(
|
|
||||||
RoomActions.update({
|
|
||||||
req: {
|
|
||||||
roomId: roomInfo.roomId,
|
|
||||||
roomName:
|
|
||||||
roomInfo.roomName.trim().length === 0
|
|
||||||
? ' '
|
|
||||||
: roomInfo.roomName.trim(),
|
|
||||||
receiveAlarm: !roomInfo.receiveAlarm,
|
|
||||||
syncAll: false
|
|
||||||
} as UpdateRequest
|
|
||||||
})
|
|
||||||
);
|
|
||||||
this.changeDetectorRef.detectChanges();
|
|
||||||
}
|
|
||||||
|
|
||||||
onDelRoom(roomInfo: RoomInfo): void {
|
|
||||||
if (!roomInfo) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const dialogRef = this.dialog.open<
|
|
||||||
ConfirmDialogComponent,
|
|
||||||
ConfirmDialogData,
|
|
||||||
ConfirmDialogResult
|
|
||||||
>(ConfirmDialogComponent, {
|
|
||||||
data: {
|
|
||||||
title: this.i18nService.t('dialog.title.exitFromRoom'),
|
|
||||||
html: this.i18nService.t('dialog.confirmExitFromRoom')
|
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
|
}
|
||||||
|
|
||||||
dialogRef
|
onSearchResultList(searchResultList: RoomInfo[]) {
|
||||||
.afterClosed()
|
this.searchResultList.emit(searchResultList);
|
||||||
.pipe(take(1))
|
|
||||||
.subscribe((result) => {
|
|
||||||
if (!!result && !!result.choice) {
|
|
||||||
this.store.dispatch(
|
|
||||||
RoomActions.del({
|
|
||||||
req: {
|
|
||||||
roomId: roomInfo.roomId
|
|
||||||
} as ExitRequest
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.changeDetectorRef.detectChanges();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
import { Observable, Subject } from 'rxjs';
|
|
||||||
|
|
||||||
import {
|
|
||||||
VirtualScrollStrategy,
|
|
||||||
CdkVirtualScrollViewport
|
|
||||||
} from '@angular/cdk/scrolling';
|
|
||||||
import { distinctUntilChanged } from 'rxjs/operators';
|
|
||||||
|
|
||||||
export class ChatGroupVirtualScrollStrategy implements VirtualScrollStrategy {
|
|
||||||
scrolledIndexChange: Observable<number>;
|
|
||||||
|
|
||||||
private indexSubject = new Subject<number>();
|
|
||||||
private viewport: CdkVirtualScrollViewport | null = null;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.scrolledIndexChange = this.indexSubject.pipe(distinctUntilChanged());
|
|
||||||
}
|
|
||||||
|
|
||||||
attach(viewport: CdkVirtualScrollViewport): void {
|
|
||||||
this.viewport = viewport;
|
|
||||||
}
|
|
||||||
detach(): void {
|
|
||||||
this.indexSubject.complete();
|
|
||||||
this.viewport = null;
|
|
||||||
}
|
|
||||||
onContentScrolled(): void {}
|
|
||||||
onDataLengthChanged(): void {}
|
|
||||||
onContentRendered(): void {}
|
|
||||||
onRenderedOffsetChanged(): void {}
|
|
||||||
scrollToIndex(index: number, behavior: ScrollBehavior): void {}
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user