0528 sync
This commit is contained in:
		
							parent
							
								
									02c2645e01
								
							
						
					
					
						commit
						176eb2bbd6
					
				
							
								
								
									
										37
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										37
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@ -3314,9 +3314,9 @@
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "@ucap/api-common": {
 | 
			
		||||
      "version": "0.0.3",
 | 
			
		||||
      "resolved": "https://nexus.loafle.net/repository/npm-all/@ucap/api-common/-/api-common-0.0.3.tgz",
 | 
			
		||||
      "integrity": "sha512-rifcCToIXdWZb9R3UXu2bXDqj/KBX3xfxHPFgx+Wp1TBUh6d+xszNYN7+mZbDKKSOYUgpVeuaF8leKkTwXUh9g==",
 | 
			
		||||
      "version": "0.0.5",
 | 
			
		||||
      "resolved": "https://nexus.loafle.net/repository/npm-all/@ucap/api-common/-/api-common-0.0.5.tgz",
 | 
			
		||||
      "integrity": "sha512-7V/Ea4FbLIKE+/ti414Spm6PQS3ZDcsHTZStLLYkMQrU7x+GbrGnHGOcvzzAQtE2SmpoNd3q6JzoYY+CK1eCkA==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "@ucap/api-external": {
 | 
			
		||||
@ -3393,8 +3393,8 @@
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "@ucap/ng-core": {
 | 
			
		||||
      "version": "file:pack/ucap-ng-core-0.0.1.tgz",
 | 
			
		||||
      "integrity": "sha512-okuTcVh/9VkF9dA1d/nsPuLL8ft2+4E77mgqfuPI2mI6IA7udQpC+hdMtyqtAN4LmT39iF1VGFv7UJYRK7fN7w==",
 | 
			
		||||
      "version": "file:pack/ucap-ng-core-0.0.7.tgz",
 | 
			
		||||
      "integrity": "sha512-ZC6LE3A0bg+REGbzDI/i1ad7mGpKsw6X0UtZ+Q8TUthHNv0DfWEieHFCgfYTRY1u022XyQ4ViOsrq9KunU1vfw==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "@ucap/ng-i18n": {
 | 
			
		||||
@ -3508,8 +3508,8 @@
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "@ucap/ng-store-chat": {
 | 
			
		||||
      "version": "file:pack/ucap-ng-store-chat-0.0.13.tgz",
 | 
			
		||||
      "integrity": "sha512-o+BCCSMxneUenRHEW47sSY22+Zt3lyr202Lg4bub9OVRbW5CVohHez8H+JwK+w+Lf8KbqG32V1ZjKLGclTpboA==",
 | 
			
		||||
      "version": "file:pack/ucap-ng-store-chat-0.0.16.tgz",
 | 
			
		||||
      "integrity": "sha512-Rwupo2Gqa+4+0ANBZLtup+mdlTU42Tj5gkGnJJ86Vylo4xQcdR+PUdedWZ/lG7DyzrfBc8ON80aUPRikpWUCow==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "@ucap/ng-store-group": {
 | 
			
		||||
@ -3528,13 +3528,8 @@
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "@ucap/ng-ui-authentication": {
 | 
			
		||||
      "version": "file:pack/ucap-ng-ui-authentication-0.0.24.tgz",
 | 
			
		||||
      "integrity": "sha512-6QMJ8dieTnbPANsBzg2Ll3HH5q6Bzl2iSM19yHq8Ct7XOmElrYqrEZmxbDyYO+aCXIAwd2t7vu+rTsHfz3XOQg==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "@ucap/ng-ui-chat": {
 | 
			
		||||
      "version": "file:pack/ucap-ng-ui-chat-0.0.9.tgz",
 | 
			
		||||
      "integrity": "sha512-6qvzcTuylkxVjsqajsLW15laOyOskxVMy238/Ju1yYvwCRyHygwS1i67APoG5tv+SWu+l38f9uWIqzfy7WYHkQ==",
 | 
			
		||||
      "version": "file:pack/ucap-ng-ui-authentication-0.0.25.tgz",
 | 
			
		||||
      "integrity": "sha512-/KgMR8JHcnOm+XwMQVhHGud61Hivi/fX0NucxUglsOguYiWL6Ms61FdRezB3wuKs5h/5+zI4QIWLdWdT8GT/Dg==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "@ucap/ng-ui-group": {
 | 
			
		||||
@ -3544,13 +3539,7 @@
 | 
			
		||||
    },
 | 
			
		||||
    "@ucap/ng-ui-material": {
 | 
			
		||||
      "version": "file:pack/ucap-ng-ui-material-0.0.4.tgz",
 | 
			
		||||
      "integrity": "sha512-ySPULAbP+nQ65hBG2VWZ2H5Hr7muuTGGNXs6A+S3lsxLaW452wM3GNyUBhvUopr8LaSsoOPpp4nK1JeC0fG6pA==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "@ucap/ng-ui-organization": {
 | 
			
		||||
      "version": "file:pack/ucap-ng-ui-organization-0.0.55.tgz",
 | 
			
		||||
      "integrity": "sha512-vfpKd3fbd+I0Od8aB2nIFfjuI7wj3Ziu/uiTEmZxKwZy7uZrNYm59BPbctKW3AQsQ4UtnLofhlBbAA7e9pT80Q==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
      "integrity": "sha512-ySPULAbP+nQ65hBG2VWZ2H5Hr7muuTGGNXs6A+S3lsxLaW452wM3GNyUBhvUopr8LaSsoOPpp4nK1JeC0fG6pA=="
 | 
			
		||||
    },
 | 
			
		||||
    "@ucap/ng-ui-skin-default": {
 | 
			
		||||
      "version": "file:pack/ucap-ng-ui-skin-default-0.0.1.tgz",
 | 
			
		||||
@ -3640,9 +3629,9 @@
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "@ucap/protocol-room": {
 | 
			
		||||
      "version": "0.0.5",
 | 
			
		||||
      "resolved": "https://nexus.loafle.net/repository/npm-all/@ucap/protocol-room/-/protocol-room-0.0.5.tgz",
 | 
			
		||||
      "integrity": "sha512-RSzLtnz5JVeDz9Y8gP17+LO6OG2NtLIPpW+JuHnqhfJyB93v2QmqqK5T7NbGYok72jRp4m7cJZEp1tLNYCKcmA==",
 | 
			
		||||
      "version": "0.0.6",
 | 
			
		||||
      "resolved": "https://nexus.loafle.net/repository/npm-all/@ucap/protocol-room/-/protocol-room-0.0.6.tgz",
 | 
			
		||||
      "integrity": "sha512-PaEztUnZgmsH/Vo4JijJxpu9DBSA4SuIBW7y+L8BcBdPtzl49jBolm08+S9vgIr8cf9MtONdU37Al+uOTVki2g==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "@ucap/protocol-service": {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										14
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								package.json
									
									
									
									
									
								
							@ -148,7 +148,7 @@
 | 
			
		||||
    "@types/moment-timezone": "^0.5.12",
 | 
			
		||||
    "@types/node": "^12.12.30",
 | 
			
		||||
    "@ucap/api": "~0.0.1",
 | 
			
		||||
    "@ucap/api-common": "~0.0.1",
 | 
			
		||||
    "@ucap/api-common": "~0.0.5",
 | 
			
		||||
    "@ucap/api-external": "~0.0.2",
 | 
			
		||||
    "@ucap/api-message": "~0.0.1",
 | 
			
		||||
    "@ucap/api-prompt": "~0.0.1",
 | 
			
		||||
@ -162,7 +162,7 @@
 | 
			
		||||
    "@ucap/ng-api-message": "file:pack/ucap-ng-api-message-0.0.1.tgz",
 | 
			
		||||
    "@ucap/ng-api-prompt": "file:pack/ucap-ng-api-prompt-0.0.1.tgz",
 | 
			
		||||
    "@ucap/ng-api-public": "file:pack/ucap-ng-api-public-0.0.1.tgz",
 | 
			
		||||
    "@ucap/ng-core": "file:pack/ucap-ng-core-0.0.1.tgz",
 | 
			
		||||
    "@ucap/ng-core": "file:pack/ucap-ng-core-0.0.7.tgz",
 | 
			
		||||
    "@ucap/ng-i18n": "file:pack/ucap-ng-i18n-0.0.6.tgz",
 | 
			
		||||
    "@ucap/ng-logger": "file:pack/ucap-ng-logger-0.0.2.tgz",
 | 
			
		||||
    "@ucap/ng-native": "file:pack/ucap-ng-native-0.0.1.tgz",
 | 
			
		||||
@ -185,15 +185,15 @@
 | 
			
		||||
    "@ucap/ng-protocol-sync": "file:pack/ucap-ng-protocol-sync-0.0.3.tgz",
 | 
			
		||||
    "@ucap/ng-protocol-umg": "file:pack/ucap-ng-protocol-umg-0.0.3.tgz",
 | 
			
		||||
    "@ucap/ng-store-authentication": "file:pack/ucap-ng-store-authentication-0.0.11.tgz",
 | 
			
		||||
    "@ucap/ng-store-chat": "file:pack/ucap-ng-store-chat-0.0.13.tgz",
 | 
			
		||||
    "@ucap/ng-store-chat": "file:pack/ucap-ng-store-chat-0.0.16.tgz",
 | 
			
		||||
    "@ucap/ng-store-group": "file:pack/ucap-ng-store-group-0.0.14.tgz",
 | 
			
		||||
    "@ucap/ng-store-organization": "file:pack/ucap-ng-store-organization-0.0.8.tgz",
 | 
			
		||||
    "@ucap/ng-ui": "file:pack/ucap-ng-ui-0.0.19.tgz",
 | 
			
		||||
    "@ucap/ng-ui-authentication": "file:pack/ucap-ng-ui-authentication-0.0.24.tgz",
 | 
			
		||||
    "@ucap/ng-ui-chat": "file:pack/ucap-ng-ui-chat-0.0.9.tgz",
 | 
			
		||||
    "@ucap/ng-ui-authentication": "file:pack/ucap-ng-ui-authentication-0.0.25.tgz",
 | 
			
		||||
    "@ucap/ng-ui-chat": "file:pack/ucap-ng-ui-chat-0.0.12.tgz",
 | 
			
		||||
    "@ucap/ng-ui-group": "file:pack/ucap-ng-ui-group-0.0.33.tgz",
 | 
			
		||||
    "@ucap/ng-ui-material": "file:pack/ucap-ng-ui-material-0.0.4.tgz",
 | 
			
		||||
    "@ucap/ng-ui-organization": "file:pack/ucap-ng-ui-organization-0.0.55.tgz",
 | 
			
		||||
    "@ucap/ng-ui-organization": "file:pack/ucap-ng-ui-organization-0.0.83.tgz",
 | 
			
		||||
    "@ucap/ng-ui-skin-default": "file:pack/ucap-ng-ui-skin-default-0.0.1.tgz",
 | 
			
		||||
    "@ucap/ng-web-socket": "file:pack/ucap-ng-web-socket-0.0.2.tgz",
 | 
			
		||||
    "@ucap/ng-web-storage": "file:pack/ucap-ng-web-storage-0.0.3.tgz",
 | 
			
		||||
@ -209,7 +209,7 @@
 | 
			
		||||
    "@ucap/protocol-option": "~0.0.7",
 | 
			
		||||
    "@ucap/protocol-ping": "~0.0.4",
 | 
			
		||||
    "@ucap/protocol-query": "~0.0.5",
 | 
			
		||||
    "@ucap/protocol-room": "~0.0.5",
 | 
			
		||||
    "@ucap/protocol-room": "~0.0.6",
 | 
			
		||||
    "@ucap/protocol-service": "~0.0.4",
 | 
			
		||||
    "@ucap/protocol-status": "~0.0.5",
 | 
			
		||||
    "@ucap/protocol-sync": "~0.0.4",
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@ucap/ng-core",
 | 
			
		||||
  "version": "0.0.1",
 | 
			
		||||
  "version": "0.0.7",
 | 
			
		||||
  "publishConfig": {
 | 
			
		||||
    "registry": "https://nexus.loafle.net/repository/npm-ucap/"
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										24
									
								
								projects/core/src/lib/utils/params.util.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								projects/core/src/lib/utils/params.util.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,24 @@
 | 
			
		||||
import { Params } from '@angular/router';
 | 
			
		||||
 | 
			
		||||
export class ParamsUtil {
 | 
			
		||||
  static getParameter<T>(params: Params, key: string, defaultValue: T): T {
 | 
			
		||||
    const v = params[key];
 | 
			
		||||
    if (undefined === v) {
 | 
			
		||||
      if (undefined !== defaultValue) {
 | 
			
		||||
        return defaultValue;
 | 
			
		||||
      }
 | 
			
		||||
      return undefined;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    switch (typeof defaultValue) {
 | 
			
		||||
      case 'boolean':
 | 
			
		||||
        return ((v as string).toLowerCase() === 'true' ? true : false) as any;
 | 
			
		||||
      case 'number':
 | 
			
		||||
        return Number(v) as any;
 | 
			
		||||
      default:
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return v;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -10,6 +10,7 @@ export interface StickerFilesInfo {
 | 
			
		||||
  index: string;
 | 
			
		||||
  path: string;
 | 
			
		||||
}
 | 
			
		||||
export const KEY_STICKER_HISTORY = 'ucap::Sticker_History';
 | 
			
		||||
export const StickerMap: StickerInfo[] = [
 | 
			
		||||
  {
 | 
			
		||||
    index: '00',
 | 
			
		||||
@ -138,15 +139,18 @@ export const StickerMap: StickerInfo[] = [
 | 
			
		||||
  }
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
const ActiveAndOrdering: string[] = ['00', '01', '02', '03', '04', '05'];
 | 
			
		||||
export const ActiveAndOrdering: string[] = ['00', '01', '02', '03', '04', '05'];
 | 
			
		||||
 | 
			
		||||
export class StickerUtil {
 | 
			
		||||
  static getStickerInfoList(): StickerInfo[] {
 | 
			
		||||
  static getStickerInfoList(
 | 
			
		||||
    stickerMap: StickerInfo[] = StickerMap,
 | 
			
		||||
    activeAndOrdering: string[] = ActiveAndOrdering
 | 
			
		||||
  ): StickerInfo[] {
 | 
			
		||||
    const rtnStickerList: StickerInfo[] = [];
 | 
			
		||||
 | 
			
		||||
    ActiveAndOrdering.forEach(idx => {
 | 
			
		||||
      const stickerInfos: StickerInfo[] = StickerMap.filter(
 | 
			
		||||
        sticker => sticker.index === idx && sticker.useYn
 | 
			
		||||
    activeAndOrdering.forEach((idx) => {
 | 
			
		||||
      const stickerInfos: StickerInfo[] = stickerMap.filter(
 | 
			
		||||
        (sticker) => sticker.index === idx && sticker.useYn
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      if (!!stickerInfos && stickerInfos.length > 0) {
 | 
			
		||||
@ -156,17 +160,4 @@ export class StickerUtil {
 | 
			
		||||
 | 
			
		||||
    return rtnStickerList;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static getStickerInfoSub(index: string): StickerFilesInfo[] {
 | 
			
		||||
    const stickerFilesList: StickerFilesInfo[] = [];
 | 
			
		||||
    const stickerInfos: StickerInfo[] = StickerMap.filter(
 | 
			
		||||
      sticker => sticker.index === index && sticker.useYn
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    if (!!stickerInfos && stickerInfos.length > 0) {
 | 
			
		||||
      stickerFilesList.concat(stickerInfos[0].fileInfos);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return stickerFilesList;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -2,6 +2,7 @@
 | 
			
		||||
 * Public API Surface of core
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
export * from './lib/utils/params.util';
 | 
			
		||||
export * from './lib/utils/sticker.util';
 | 
			
		||||
export * from './lib/utils/string.util';
 | 
			
		||||
export * from './lib/utils/window.util';
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@ucap/ng-store-chat",
 | 
			
		||||
  "version": "0.0.13",
 | 
			
		||||
  "version": "0.0.16",
 | 
			
		||||
  "publishConfig": {
 | 
			
		||||
    "registry": "https://nexus.loafle.net/repository/npm-ucap/"
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
@ -83,7 +83,22 @@ export const fileInfosFailure = createAction(
 | 
			
		||||
 */
 | 
			
		||||
export const addEvent = createAction(
 | 
			
		||||
  '[ucap::chat::chatting] addEvent',
 | 
			
		||||
  props<{ req: FileInfoRequest }>()
 | 
			
		||||
  props<{
 | 
			
		||||
    roomId: string;
 | 
			
		||||
    info: Info<EventJson>;
 | 
			
		||||
    SVC_TYPE?: number;
 | 
			
		||||
    SSVC_TYPE?: number;
 | 
			
		||||
  }>()
 | 
			
		||||
);
 | 
			
		||||
/**
 | 
			
		||||
 * add new event Success.
 | 
			
		||||
 */
 | 
			
		||||
export const addEventSuccess = createAction(
 | 
			
		||||
  '[ucap::chat::chatting] addEvent Success',
 | 
			
		||||
  props<{
 | 
			
		||||
    roomId: string;
 | 
			
		||||
    info: Info<EventJson>;
 | 
			
		||||
  }>()
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
export const read = createAction(
 | 
			
		||||
@ -105,3 +120,26 @@ export const readFailure = createAction(
 | 
			
		||||
  '[ucap::chat::chatting] read Failure',
 | 
			
		||||
  props<{ error: any }>()
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
export const send = createAction(
 | 
			
		||||
  '[ucap::chat::chatting] Send',
 | 
			
		||||
  props<{ senderSeq: string; req: SendEventRequest }>()
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
export const sendSuccess = createAction(
 | 
			
		||||
  '[ucap::chat::chatting] Send Success',
 | 
			
		||||
  props<{
 | 
			
		||||
    senderSeq: string;
 | 
			
		||||
    res: SendEventResponse;
 | 
			
		||||
  }>()
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
export const sendFailure = createAction(
 | 
			
		||||
  '[ucap::chat::chatting] Send Failure',
 | 
			
		||||
  props<{ error: any }>()
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
export const sendNotification = createAction(
 | 
			
		||||
  '[ucap::chat::chatting] Send Notification',
 | 
			
		||||
  props<{ noti: SendNotification }>()
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
@ -5,13 +5,16 @@ import {
 | 
			
		||||
  map,
 | 
			
		||||
  catchError,
 | 
			
		||||
  exhaustMap,
 | 
			
		||||
  concatMap,
 | 
			
		||||
  withLatestFrom,
 | 
			
		||||
  debounceTime
 | 
			
		||||
} from 'rxjs/operators';
 | 
			
		||||
 | 
			
		||||
import { Injectable, Inject } from '@angular/core';
 | 
			
		||||
 | 
			
		||||
import { Store } from '@ngrx/store';
 | 
			
		||||
import { Store, select } from '@ngrx/store';
 | 
			
		||||
import { Actions, createEffect, ofType } from '@ngrx/effects';
 | 
			
		||||
import { Dictionary } from '@ngrx/entity';
 | 
			
		||||
 | 
			
		||||
import { EventProtocolService } from '@ucap/ng-protocol-event';
 | 
			
		||||
import { RoomProtocolService } from '@ucap/ng-protocol-room';
 | 
			
		||||
@ -27,13 +30,24 @@ import {
 | 
			
		||||
  readSuccess,
 | 
			
		||||
  fileInfos,
 | 
			
		||||
  fileInfosFailure,
 | 
			
		||||
  fileInfosSuccess
 | 
			
		||||
  fileInfosSuccess,
 | 
			
		||||
  send,
 | 
			
		||||
  sendSuccess,
 | 
			
		||||
  sendFailure,
 | 
			
		||||
  addEvent,
 | 
			
		||||
  addEventSuccess
 | 
			
		||||
} from './actions';
 | 
			
		||||
 | 
			
		||||
import { InfoRequest, ReadResponse, FileType } from '@ucap/protocol-event';
 | 
			
		||||
import {
 | 
			
		||||
  InfoRequest,
 | 
			
		||||
  ReadResponse,
 | 
			
		||||
  FileType,
 | 
			
		||||
  EventType
 | 
			
		||||
} from '@ucap/protocol-event';
 | 
			
		||||
 | 
			
		||||
import { ModuleConfig } from '../../config/module-config';
 | 
			
		||||
import { _MODULE_CONFIG } from '../../config/token';
 | 
			
		||||
import { Chatting } from './state';
 | 
			
		||||
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class Effects {
 | 
			
		||||
@ -158,6 +172,89 @@ export class Effects {
 | 
			
		||||
    { dispatch: false }
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  addEvent$ = createEffect(
 | 
			
		||||
    () => {
 | 
			
		||||
      return this.actions$.pipe(
 | 
			
		||||
        ofType(addEvent),
 | 
			
		||||
        withLatestFrom(
 | 
			
		||||
          this.store.pipe(
 | 
			
		||||
            select(
 | 
			
		||||
              (state: any) =>
 | 
			
		||||
                state.chat.chatting.chattings.entities as Dictionary<Chatting>
 | 
			
		||||
            )
 | 
			
		||||
          ),
 | 
			
		||||
          this.store.pipe(
 | 
			
		||||
            select((state: any) => state.chat.chatting.activeRoomId)
 | 
			
		||||
          )
 | 
			
		||||
        ),
 | 
			
		||||
        tap(([action, chattings, activeRoomId]) => {
 | 
			
		||||
          // Room in chattings state >> event add
 | 
			
		||||
          if (!!chattings && !!chattings[action.roomId]) {
 | 
			
		||||
            if (action.info.type === EventType.File) {
 | 
			
		||||
              // Retrieve event of FileType in rooms
 | 
			
		||||
              this.store.dispatch(
 | 
			
		||||
                fileInfos({
 | 
			
		||||
                  req: {
 | 
			
		||||
                    roomId: action.roomId,
 | 
			
		||||
                    type: FileType.All
 | 
			
		||||
                  }
 | 
			
		||||
                })
 | 
			
		||||
              );
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          // room > rooms :: finalEvent-Infos refresh
 | 
			
		||||
          this.store.dispatch(
 | 
			
		||||
            addEventSuccess({
 | 
			
		||||
              roomId: action.roomId,
 | 
			
		||||
              info: action.info
 | 
			
		||||
            })
 | 
			
		||||
          );
 | 
			
		||||
        })
 | 
			
		||||
      );
 | 
			
		||||
    },
 | 
			
		||||
    { dispatch: false }
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  send$ = createEffect(() =>
 | 
			
		||||
    this.actions$.pipe(
 | 
			
		||||
      ofType(send),
 | 
			
		||||
      concatMap((action) =>
 | 
			
		||||
        this.eventProtocolService.send(action.req).pipe(
 | 
			
		||||
          map((res) => {
 | 
			
		||||
            return sendSuccess({
 | 
			
		||||
              senderSeq: action.senderSeq,
 | 
			
		||||
              res
 | 
			
		||||
            });
 | 
			
		||||
          }),
 | 
			
		||||
          catchError((error) => of(sendFailure({ error })))
 | 
			
		||||
        )
 | 
			
		||||
      )
 | 
			
		||||
    )
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  sendSuccess$ = createEffect(
 | 
			
		||||
    () => {
 | 
			
		||||
      return this.actions$.pipe(
 | 
			
		||||
        ofType(sendSuccess),
 | 
			
		||||
        tap((action) => {
 | 
			
		||||
          const res = action.res;
 | 
			
		||||
          console.log('sendSuccess', action);
 | 
			
		||||
 | 
			
		||||
          this.store.dispatch(
 | 
			
		||||
            addEvent({
 | 
			
		||||
              roomId: res.roomId,
 | 
			
		||||
              info: res.info,
 | 
			
		||||
              SVC_TYPE: res.SVC_TYPE,
 | 
			
		||||
              SSVC_TYPE: res.SSVC_TYPE
 | 
			
		||||
            })
 | 
			
		||||
          );
 | 
			
		||||
        })
 | 
			
		||||
      );
 | 
			
		||||
    },
 | 
			
		||||
    { dispatch: false }
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    private actions$: Actions,
 | 
			
		||||
    private store: Store<any>,
 | 
			
		||||
 | 
			
		||||
@ -15,7 +15,8 @@ import {
 | 
			
		||||
  eventsFailure,
 | 
			
		||||
  readSuccess,
 | 
			
		||||
  fileInfosSuccess,
 | 
			
		||||
  fileInfosFailure
 | 
			
		||||
  fileInfosFailure,
 | 
			
		||||
  addEvent
 | 
			
		||||
} from './actions';
 | 
			
		||||
 | 
			
		||||
export const reducer = createReducer(
 | 
			
		||||
@ -163,5 +164,29 @@ export const reducer = createReducer(
 | 
			
		||||
        ...state.chattings
 | 
			
		||||
      })
 | 
			
		||||
    };
 | 
			
		||||
  }),
 | 
			
		||||
 | 
			
		||||
  on(addEvent, (state, action) => {
 | 
			
		||||
    const roomId = action.roomId;
 | 
			
		||||
    const eventInfo = action.info;
 | 
			
		||||
 | 
			
		||||
    const chatting = state.chattings.entities[roomId];
 | 
			
		||||
 | 
			
		||||
    if (!!chatting) {
 | 
			
		||||
      return {
 | 
			
		||||
        ...state,
 | 
			
		||||
        chattings: adapterChatting.upsertOne(
 | 
			
		||||
          {
 | 
			
		||||
            ...chatting,
 | 
			
		||||
            eventList: adapterEventList.upsertOne(eventInfo, {
 | 
			
		||||
              ...chatting.eventList
 | 
			
		||||
            })
 | 
			
		||||
          },
 | 
			
		||||
          { ...state.chattings }
 | 
			
		||||
        )
 | 
			
		||||
      };
 | 
			
		||||
    } else {
 | 
			
		||||
      return state;
 | 
			
		||||
    }
 | 
			
		||||
  })
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
@ -119,6 +119,20 @@ export const roomFailure = createAction(
 | 
			
		||||
  '[ucap::chat::room] room Failure',
 | 
			
		||||
  props<{ error: any }>()
 | 
			
		||||
);
 | 
			
		||||
/**
 | 
			
		||||
 * Success of rooms2 request
 | 
			
		||||
 * RoomUserData is detail, short type both.
 | 
			
		||||
 */
 | 
			
		||||
export const room2Success = createAction(
 | 
			
		||||
  '[ucap::chat::room] room2 Success',
 | 
			
		||||
  props<{
 | 
			
		||||
    roomInfo: RoomInfo;
 | 
			
		||||
    roomUserInfo: {
 | 
			
		||||
      userInfoShortList: UserInfoShort[];
 | 
			
		||||
      userInfoList: RoomUserInfo[];
 | 
			
		||||
    };
 | 
			
		||||
  }>()
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * create room
 | 
			
		||||
 | 
			
		||||
@ -28,10 +28,10 @@ import {
 | 
			
		||||
} from '@ucap/protocol-room';
 | 
			
		||||
 | 
			
		||||
import { RoomProtocolService } from '@ucap/ng-protocol-room';
 | 
			
		||||
 | 
			
		||||
import { SyncProtocolService } from '@ucap/ng-protocol-sync';
 | 
			
		||||
 | 
			
		||||
import { LoginActions } from '@ucap/ng-store-authentication';
 | 
			
		||||
import { addEventSuccess } from '../Chatting/actions';
 | 
			
		||||
 | 
			
		||||
import { RoomSelector } from '../state';
 | 
			
		||||
 | 
			
		||||
@ -77,8 +77,11 @@ import {
 | 
			
		||||
  delMulti,
 | 
			
		||||
  delMultiSuccess,
 | 
			
		||||
  delMultiFailure,
 | 
			
		||||
  selectedRoom
 | 
			
		||||
  selectedRoom,
 | 
			
		||||
  room2Success
 | 
			
		||||
} from './actions';
 | 
			
		||||
import { Router } from '@angular/router';
 | 
			
		||||
import { LocaleCode } from '@ucap/core';
 | 
			
		||||
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class Effects {
 | 
			
		||||
@ -100,8 +103,6 @@ export class Effects {
 | 
			
		||||
            isDetail: false
 | 
			
		||||
          };
 | 
			
		||||
 | 
			
		||||
          console.log(req);
 | 
			
		||||
 | 
			
		||||
          // retrieve room info
 | 
			
		||||
          this.store.dispatch(room({ req }));
 | 
			
		||||
 | 
			
		||||
@ -151,13 +152,25 @@ export class Effects {
 | 
			
		||||
  room$ = createEffect(() => {
 | 
			
		||||
    return this.actions$.pipe(
 | 
			
		||||
      ofType(room),
 | 
			
		||||
      map((action) => action.req),
 | 
			
		||||
      switchMap((req) => {
 | 
			
		||||
        return this.roomProtocolService.info(req).pipe(
 | 
			
		||||
      switchMap((action) => {
 | 
			
		||||
        const req = action.req;
 | 
			
		||||
        // // CASE :: RoomUser Data 중 Detail data 만 수집.
 | 
			
		||||
        // return this.roomProtocolService.info(req).pipe(
 | 
			
		||||
        //   map((res) =>
 | 
			
		||||
        //     roomSuccess({
 | 
			
		||||
        //       roomInfo: res.roomInfo,
 | 
			
		||||
        //       userInfoList: res.userInfoList
 | 
			
		||||
        //     })
 | 
			
		||||
        //   ),
 | 
			
		||||
        //   catchError((error) => of(roomFailure({ error })))
 | 
			
		||||
        // );
 | 
			
		||||
 | 
			
		||||
        // CASE :: RoomUser Data 중 Detail data, Short data 수집.
 | 
			
		||||
        return this.roomProtocolService.info2(req).pipe(
 | 
			
		||||
          map((res) =>
 | 
			
		||||
            roomSuccess({
 | 
			
		||||
            room2Success({
 | 
			
		||||
              roomInfo: res.roomInfo,
 | 
			
		||||
              userInfoList: res.userInfoList
 | 
			
		||||
              roomUserInfo: res.roomUserInfo
 | 
			
		||||
            })
 | 
			
		||||
          ),
 | 
			
		||||
          catchError((error) => of(roomFailure({ error })))
 | 
			
		||||
@ -166,19 +179,40 @@ export class Effects {
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  create$ = createEffect(() =>
 | 
			
		||||
    this.actions$.pipe(
 | 
			
		||||
      ofType(create),
 | 
			
		||||
      map((action) => action.req),
 | 
			
		||||
      exhaustMap((req) => {
 | 
			
		||||
        return this.roomProtocolService.open(req).pipe(
 | 
			
		||||
          map((res: CreateResponse) => {
 | 
			
		||||
            return createSuccess({ res });
 | 
			
		||||
          }),
 | 
			
		||||
          catchError((error) => of(createFailure({ error })))
 | 
			
		||||
        );
 | 
			
		||||
      })
 | 
			
		||||
    )
 | 
			
		||||
  create$ = createEffect(
 | 
			
		||||
    () => {
 | 
			
		||||
      return this.actions$.pipe(
 | 
			
		||||
        ofType(create),
 | 
			
		||||
        map((action) => action.req),
 | 
			
		||||
        exhaustMap((req) => {
 | 
			
		||||
          return this.roomProtocolService.open(req).pipe(
 | 
			
		||||
            map((res: CreateResponse) => {
 | 
			
		||||
              console.log('CreateResponse', res);
 | 
			
		||||
 | 
			
		||||
              this.store.dispatch(createSuccess({ res }));
 | 
			
		||||
 | 
			
		||||
              this.router.navigate(
 | 
			
		||||
                [
 | 
			
		||||
                  'chat',
 | 
			
		||||
                  {
 | 
			
		||||
                    outlets: { content: 'chatroom' }
 | 
			
		||||
                  }
 | 
			
		||||
                ],
 | 
			
		||||
                {
 | 
			
		||||
                  queryParams: { roomId: res.roomId }
 | 
			
		||||
                }
 | 
			
		||||
              );
 | 
			
		||||
 | 
			
		||||
              // if (!res.newRoom) {
 | 
			
		||||
              // } else {
 | 
			
		||||
              // }
 | 
			
		||||
            }),
 | 
			
		||||
            catchError((error) => of(createFailure({ error })))
 | 
			
		||||
          );
 | 
			
		||||
        })
 | 
			
		||||
      );
 | 
			
		||||
    },
 | 
			
		||||
    { dispatch: false }
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  createTimer$ = createEffect(() =>
 | 
			
		||||
@ -390,9 +424,30 @@ export class Effects {
 | 
			
		||||
    );
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  /*******************************************************************
 | 
			
		||||
   * [Chatting Action watching.]
 | 
			
		||||
   *******************************************************************/
 | 
			
		||||
  addEventSuccess$ = createEffect(
 | 
			
		||||
    () => {
 | 
			
		||||
      return this.actions$.pipe(
 | 
			
		||||
        ofType(addEventSuccess),
 | 
			
		||||
        withLatestFrom(this.store.pipe(select(RoomSelector.rooms))),
 | 
			
		||||
        map(([action, roomList]) => {
 | 
			
		||||
          const roomId = action.roomId;
 | 
			
		||||
 | 
			
		||||
          if (!roomList.find((roomInfo) => roomInfo.roomId === roomId)) {
 | 
			
		||||
            this.store.dispatch(rooms({ localeCode: LocaleCode.Korean }));
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
      );
 | 
			
		||||
    },
 | 
			
		||||
    { dispatch: false }
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    private actions$: Actions,
 | 
			
		||||
    private store: Store<any>,
 | 
			
		||||
    private router: Router,
 | 
			
		||||
    private syncProtocolService: SyncProtocolService,
 | 
			
		||||
    private roomProtocolService: RoomProtocolService
 | 
			
		||||
  ) {}
 | 
			
		||||
 | 
			
		||||
@ -24,9 +24,12 @@ import {
 | 
			
		||||
  delSuccess,
 | 
			
		||||
  rooms2Success,
 | 
			
		||||
  delMultiSuccess,
 | 
			
		||||
  updateSuccess
 | 
			
		||||
  updateSuccess,
 | 
			
		||||
  room2Success,
 | 
			
		||||
  createSuccess
 | 
			
		||||
} from './actions';
 | 
			
		||||
import { userInfo } from 'os';
 | 
			
		||||
import { Info, EventJson } from '@ucap/protocol-event';
 | 
			
		||||
import { ChatUtil } from '../../utils/chat.util';
 | 
			
		||||
 | 
			
		||||
export const reducer = createReducer(
 | 
			
		||||
  initialState,
 | 
			
		||||
@ -136,6 +139,49 @@ export const reducer = createReducer(
 | 
			
		||||
    };
 | 
			
		||||
  }),
 | 
			
		||||
 | 
			
		||||
  on(room2Success, (state, action) => {
 | 
			
		||||
    const roomUserMapList: RoomUserMap[] = [];
 | 
			
		||||
    const roomUserShortMapList: RoomUserShortMap[] = [];
 | 
			
		||||
 | 
			
		||||
    if (
 | 
			
		||||
      !!action.roomUserInfo.userInfoList &&
 | 
			
		||||
      0 < action.roomUserInfo.userInfoList.length
 | 
			
		||||
    ) {
 | 
			
		||||
      roomUserMapList.push({
 | 
			
		||||
        roomId: action.roomInfo.roomId,
 | 
			
		||||
        userInfos: action.roomUserInfo.userInfoList
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    if (
 | 
			
		||||
      !!action.roomUserInfo.userInfoShortList &&
 | 
			
		||||
      0 < action.roomUserInfo.userInfoShortList.length
 | 
			
		||||
    ) {
 | 
			
		||||
      roomUserShortMapList.push({
 | 
			
		||||
        roomId: action.roomInfo.roomId,
 | 
			
		||||
        userInfos: action.roomUserInfo.userInfoShortList
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      ...state,
 | 
			
		||||
      rooms: adapterRoom.upsertOne(action.roomInfo, {
 | 
			
		||||
        ...state.rooms
 | 
			
		||||
      }),
 | 
			
		||||
      roomUsers:
 | 
			
		||||
        0 < roomUserMapList.length
 | 
			
		||||
          ? adapterRoomUser.upsertMany(roomUserMapList, {
 | 
			
		||||
              ...state.roomUsers
 | 
			
		||||
            })
 | 
			
		||||
          : state.roomUsers,
 | 
			
		||||
      roomUsersShort:
 | 
			
		||||
        0 < roomUserShortMapList.length
 | 
			
		||||
          ? adapterRoomUserShort.upsertMany(roomUserShortMapList, {
 | 
			
		||||
              ...state.roomUsersShort
 | 
			
		||||
            })
 | 
			
		||||
          : state.roomUsersShort
 | 
			
		||||
    };
 | 
			
		||||
  }),
 | 
			
		||||
 | 
			
		||||
  on(excludeUserSuccess, (state, action) => {
 | 
			
		||||
    const roomId = action.roomId;
 | 
			
		||||
    const roomUserMap = state.roomUsers.entities[roomId];
 | 
			
		||||
@ -191,6 +237,41 @@ export const reducer = createReducer(
 | 
			
		||||
    };
 | 
			
		||||
  }),
 | 
			
		||||
 | 
			
		||||
  on(createSuccess, (state, action) => {
 | 
			
		||||
    const standby = state.standbyRooms;
 | 
			
		||||
    const curRoomId = action.res.roomId;
 | 
			
		||||
    if (standby.findIndex((roomId) => roomId === curRoomId) > -1) {
 | 
			
		||||
      // Exist.
 | 
			
		||||
      return state;
 | 
			
		||||
    } else {
 | 
			
		||||
      // Not Exist.
 | 
			
		||||
      return {
 | 
			
		||||
        ...state,
 | 
			
		||||
        standbyRooms: [...state.standbyRooms, curRoomId]
 | 
			
		||||
      };
 | 
			
		||||
    }
 | 
			
		||||
  }),
 | 
			
		||||
 | 
			
		||||
  on(delSuccess, (state, action) => {
 | 
			
		||||
    const roomId = action.res.roomId;
 | 
			
		||||
    const room = state.rooms.entities[roomId];
 | 
			
		||||
 | 
			
		||||
    if (!room) {
 | 
			
		||||
      return state;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      ...state,
 | 
			
		||||
      rooms: adapterRoom.removeOne(roomId, { ...state.rooms }),
 | 
			
		||||
      roomUsers: adapterRoomUser.removeOne(roomId, {
 | 
			
		||||
        ...state.roomUsers
 | 
			
		||||
      }),
 | 
			
		||||
      roomUsersShort: adapterRoomUserShort.removeOne(roomId, {
 | 
			
		||||
        ...state.roomUsersShort
 | 
			
		||||
      })
 | 
			
		||||
    };
 | 
			
		||||
  }),
 | 
			
		||||
 | 
			
		||||
  on(updateSuccess, (state, action) => {
 | 
			
		||||
    const roomInfo = {
 | 
			
		||||
      ...state.rooms.entities[action.res.roomId],
 | 
			
		||||
@ -243,9 +324,9 @@ export const reducer = createReducer(
 | 
			
		||||
    };
 | 
			
		||||
  }),
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
  /*******************************************************************
 | 
			
		||||
   * [Chatting Action watching.]
 | 
			
		||||
   */
 | 
			
		||||
   *******************************************************************/
 | 
			
		||||
  on(chattingActions.readSuccess, (state, action) => {
 | 
			
		||||
    const roomId = action.roomId;
 | 
			
		||||
    const trgtUserSeq = action.SENDER_SEQ;
 | 
			
		||||
@ -279,7 +360,10 @@ export const reducer = createReducer(
 | 
			
		||||
        userInfos: state.roomUsersShort.entities[roomId].userInfos.map(
 | 
			
		||||
          (roomUserInfo) => {
 | 
			
		||||
            if (roomUserInfo.seq === Number(trgtUserSeq)) {
 | 
			
		||||
              return { ...roomUserInfo, lastReadEventSeq: action.lastReadSeq };
 | 
			
		||||
              return {
 | 
			
		||||
                ...roomUserInfo,
 | 
			
		||||
                lastReadEventSeq: action.lastReadSeq
 | 
			
		||||
              };
 | 
			
		||||
            } else {
 | 
			
		||||
              return roomUserInfo;
 | 
			
		||||
            }
 | 
			
		||||
@ -301,5 +385,44 @@ export const reducer = createReducer(
 | 
			
		||||
          })
 | 
			
		||||
        : state.roomUsersShort
 | 
			
		||||
    };
 | 
			
		||||
  }),
 | 
			
		||||
 | 
			
		||||
  on(chattingActions.addEventSuccess, (state, action) => {
 | 
			
		||||
    const roomId = action.roomId;
 | 
			
		||||
    const info: Info<EventJson> = action.info;
 | 
			
		||||
 | 
			
		||||
    if (!roomId || !info) {
 | 
			
		||||
      return state;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const currentRoomInfo = state.rooms.entities[roomId];
 | 
			
		||||
    const fixedStandByRooms = state.standbyRooms.filter(
 | 
			
		||||
      (standbyRoomId) => standbyRoomId !== roomId
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    if (!!currentRoomInfo) {
 | 
			
		||||
      const finalEventMessage:
 | 
			
		||||
        | string
 | 
			
		||||
        | null = ChatUtil.convertFinalEventMessage(
 | 
			
		||||
        action.info.type,
 | 
			
		||||
        action.info.sentMessageJson || action.info.sentMessage
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      const roomInfo = {
 | 
			
		||||
        ...currentRoomInfo,
 | 
			
		||||
        finalEventType: info.type,
 | 
			
		||||
        finalEventDate: info.sendDate,
 | 
			
		||||
        finalEventMessage,
 | 
			
		||||
        finalEventSeq: info.seq
 | 
			
		||||
      } as RoomInfo;
 | 
			
		||||
 | 
			
		||||
      return {
 | 
			
		||||
        ...state,
 | 
			
		||||
        rooms: adapterRoom.upsertOne(roomInfo, { ...state.rooms }),
 | 
			
		||||
        standbyRooms: fixedStandByRooms
 | 
			
		||||
      };
 | 
			
		||||
    } else {
 | 
			
		||||
      return state;
 | 
			
		||||
    }
 | 
			
		||||
  })
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
@ -47,6 +47,7 @@ export interface State {
 | 
			
		||||
  rooms: RoomState;
 | 
			
		||||
  roomUsers: RoomUserState;
 | 
			
		||||
  roomUsersShort: RoomUserShortState;
 | 
			
		||||
  standbyRooms: string[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const roomInitialState: RoomState = adapterRoom.getInitialState({
 | 
			
		||||
@ -60,7 +61,8 @@ const roomUserShortInitialState: RoomUserShortState = adapterRoomUserShort.getIn
 | 
			
		||||
export const initialState: State = {
 | 
			
		||||
  rooms: roomInitialState,
 | 
			
		||||
  roomUsers: roomUserInitialState,
 | 
			
		||||
  roomUsersShort: roomUserShortInitialState
 | 
			
		||||
  roomUsersShort: roomUserShortInitialState,
 | 
			
		||||
  standbyRooms: []
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const {
 | 
			
		||||
@ -128,6 +130,10 @@ export function selectors<S>(selector: Selector<any, State>) {
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
    ),
 | 
			
		||||
    standbyRooms: createSelector(
 | 
			
		||||
      selector,
 | 
			
		||||
      (state: State) => state.standbyRooms
 | 
			
		||||
    ),
 | 
			
		||||
    unreadTotal: createSelector(
 | 
			
		||||
      selectRooms,
 | 
			
		||||
      selectAllForRoom,
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										138
									
								
								projects/store-chat/src/lib/utils/chat.util.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								projects/store-chat/src/lib/utils/chat.util.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,138 @@
 | 
			
		||||
import {
 | 
			
		||||
  EventJson,
 | 
			
		||||
  EventType,
 | 
			
		||||
  FileEventJson,
 | 
			
		||||
  FileType,
 | 
			
		||||
  VideoConferenceEventJson,
 | 
			
		||||
  VideoConferenceContentsType,
 | 
			
		||||
  MassTextEventJson,
 | 
			
		||||
  TranslationEventJson,
 | 
			
		||||
  MassTranslationEventJson,
 | 
			
		||||
  PlanEventJson,
 | 
			
		||||
  PlanContentType
 | 
			
		||||
} from '@ucap/protocol-event';
 | 
			
		||||
 | 
			
		||||
export class ChatUtil {
 | 
			
		||||
  public static convertFinalEventMessage(
 | 
			
		||||
    eventType: EventType,
 | 
			
		||||
    finalEventMessage: EventJson
 | 
			
		||||
  ): string | null {
 | 
			
		||||
    let eventMessage: string = null;
 | 
			
		||||
 | 
			
		||||
    switch (eventType) {
 | 
			
		||||
      case EventType.Join:
 | 
			
		||||
      case EventType.Exit:
 | 
			
		||||
      case EventType.ForcedExit:
 | 
			
		||||
      case EventType.RenameRoom:
 | 
			
		||||
      case EventType.NotificationForTimerRoom:
 | 
			
		||||
      case EventType.GuideForRoomTimerChanged:
 | 
			
		||||
        {
 | 
			
		||||
          /**
 | 
			
		||||
           * 해당 타입은 메시지를 갱신하지 않는다.
 | 
			
		||||
           * @description Edit with ui-chat > messages.component.ts
 | 
			
		||||
           */
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
      case EventType.Sticker:
 | 
			
		||||
        {
 | 
			
		||||
          eventMessage = '스티커';
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
      case EventType.File:
 | 
			
		||||
        {
 | 
			
		||||
          const m = finalEventMessage as FileEventJson;
 | 
			
		||||
 | 
			
		||||
          if (FileType.Image === m.fileType) {
 | 
			
		||||
            eventMessage = '이미지';
 | 
			
		||||
          } else {
 | 
			
		||||
            eventMessage = '첨부파일';
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
      case EventType.VideoConference:
 | 
			
		||||
        {
 | 
			
		||||
          const m = finalEventMessage as VideoConferenceEventJson;
 | 
			
		||||
          switch (m.contents) {
 | 
			
		||||
            case VideoConferenceContentsType.Now:
 | 
			
		||||
              eventMessage = '화상회의가 개설되었습니다.';
 | 
			
		||||
              break;
 | 
			
		||||
            case VideoConferenceContentsType.New:
 | 
			
		||||
              eventMessage = '화상회의가 등록되었습니다.';
 | 
			
		||||
              break;
 | 
			
		||||
            case VideoConferenceContentsType.Update:
 | 
			
		||||
              eventMessage = '화상회의가 수정되었습니다.';
 | 
			
		||||
              break;
 | 
			
		||||
            case VideoConferenceContentsType.Delete:
 | 
			
		||||
              eventMessage = '화상회의가 취소되었습니다.';
 | 
			
		||||
              break;
 | 
			
		||||
            default:
 | 
			
		||||
              eventMessage = '화상회의';
 | 
			
		||||
              break;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
      case EventType.MassText:
 | 
			
		||||
        {
 | 
			
		||||
          const m = finalEventMessage as MassTextEventJson;
 | 
			
		||||
          eventMessage = m.content;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
      case EventType.Translation:
 | 
			
		||||
        {
 | 
			
		||||
          const m = finalEventMessage as TranslationEventJson;
 | 
			
		||||
          eventMessage = m.original;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
      case EventType.MassTranslation:
 | 
			
		||||
        {
 | 
			
		||||
          const m = finalEventMessage as MassTranslationEventJson;
 | 
			
		||||
          eventMessage = m.original;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
      case EventType.Plan:
 | 
			
		||||
        {
 | 
			
		||||
          const m = finalEventMessage as PlanEventJson;
 | 
			
		||||
          switch (m.contents) {
 | 
			
		||||
            case PlanContentType.New:
 | 
			
		||||
              eventMessage = '새로운 일정이 등록되었습니다.';
 | 
			
		||||
              break;
 | 
			
		||||
            case PlanContentType.Update:
 | 
			
		||||
              eventMessage = '일정이 수정되었습니다.';
 | 
			
		||||
              break;
 | 
			
		||||
            case PlanContentType.Delete:
 | 
			
		||||
              eventMessage = '일정이 취소되었습니다.';
 | 
			
		||||
              break;
 | 
			
		||||
            default:
 | 
			
		||||
              eventMessage = '일정이 업데이트 되었습니다.';
 | 
			
		||||
              break;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
      case EventType.NotificationForiOSCapture:
 | 
			
		||||
        {
 | 
			
		||||
          const m = finalEventMessage as string;
 | 
			
		||||
          eventMessage = `${m}님이 대화내용을 캡쳐하였습니다.`;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
      case EventType.AllimElephant: // [daesang] 알림
 | 
			
		||||
        {
 | 
			
		||||
          eventMessage = '코끼리 알림';
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
      case EventType.AllimTms: // [daesang] 알림
 | 
			
		||||
        {
 | 
			
		||||
          eventMessage = 'TMS 알림';
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        {
 | 
			
		||||
          const m = finalEventMessage as string;
 | 
			
		||||
          eventMessage = m;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    return eventMessage;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@ucap/ng-ui-authentication",
 | 
			
		||||
  "version": "0.0.24",
 | 
			
		||||
  "version": "0.0.25",
 | 
			
		||||
  "publishConfig": {
 | 
			
		||||
    "registry": "https://nexus.loafle.net/repository/npm-ucap/"
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
@ -6,7 +6,7 @@
 | 
			
		||||
      class="ucap-authentication-login-input-field"
 | 
			
		||||
      [style.display]="!!fixedCompanyCode ? 'none' : 'block'"
 | 
			
		||||
    >
 | 
			
		||||
      <mat-form-field>
 | 
			
		||||
      <mat-form-field color="accent">
 | 
			
		||||
        <mat-label>{{ 'login.fields.company' | ucapI18n }}</mat-label>
 | 
			
		||||
        <mat-select
 | 
			
		||||
          [formControl]="companyCodeFormControl"
 | 
			
		||||
@ -26,16 +26,27 @@
 | 
			
		||||
    <div class="ucap-authentication-login-input-field">
 | 
			
		||||
      <!--<span class="input-icon"><i class="mid mdi-account-tie-outline"></i></span>-->
 | 
			
		||||
      <span class="ucap-authentication-login-input-icon">
 | 
			
		||||
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20.82 22">
 | 
			
		||||
          <path
 | 
			
		||||
            d="M14.39,11.88a5.7,5.7,0,1,0-4.78,0A10.41,10.41,0,0,0,1.59,22v1H22.41V22A10.41,10.41,0,0,0,14.39,11.88Z"
 | 
			
		||||
            transform="translate(-1.59 -1)"
 | 
			
		||||
            style="fill: #fff;"
 | 
			
		||||
          />
 | 
			
		||||
          <path
 | 
			
		||||
            d="M14.39,11.88a5.7,5.7,0,1,0-4.78,0A10.41,10.41,0,0,0,1.59,22v1H22.41V22A10.41,10.41,0,0,0,14.39,11.88ZM8.3,6.7A3.71,3.71,0,1,1,12,10.41,3.7,3.7,0,0,1,8.3,6.7ZM3.65,21a8.42,8.42,0,0,1,7.58-7.37L10,16.58l2,2,2-2-1.23-2.95A8.42,8.42,0,0,1,20.35,21Z"
 | 
			
		||||
            transform="translate(-1.59 -1)"
 | 
			
		||||
          />
 | 
			
		||||
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
 | 
			
		||||
          <path d="M0 0H24V24H0z" style="fill: none;" />
 | 
			
		||||
          <g transform="translate(.118 -1)">
 | 
			
		||||
            <path
 | 
			
		||||
              d="M58.571 48.146a8.3 8.3 0 1 0-16.571 0"
 | 
			
		||||
              transform="translate(-38.403 -25.592)"
 | 
			
		||||
              style="
 | 
			
		||||
                stroke-miterlimit: 10;
 | 
			
		||||
                stroke: #4c4c4c;
 | 
			
		||||
                stroke-width: 2px;
 | 
			
		||||
                fill: none;
 | 
			
		||||
              "
 | 
			
		||||
            />
 | 
			
		||||
            <g
 | 
			
		||||
              transform="translate(7.037 3.808)"
 | 
			
		||||
              style="stroke: #4c4c4c; stroke-width: 2px; fill: none;"
 | 
			
		||||
            >
 | 
			
		||||
              <circle cx="4.5" cy="4.5" r="4.5" style="stroke: none;" />
 | 
			
		||||
              <circle cx="4.5" cy="4.5" r="3.5" style="fill: none;" />
 | 
			
		||||
            </g>
 | 
			
		||||
          </g>
 | 
			
		||||
        </svg>
 | 
			
		||||
      </span>
 | 
			
		||||
      <mat-form-field>
 | 
			
		||||
@ -47,30 +58,41 @@
 | 
			
		||||
    <div class="ucap-authentication-login-input-field">
 | 
			
		||||
      <!--<span class="input-icon"><i class="mid mdi-lock-outline"></i></span>-->
 | 
			
		||||
      <span class="ucap-authentication-login-input-icon">
 | 
			
		||||
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 22.07">
 | 
			
		||||
          <title>login-lock</title>
 | 
			
		||||
          <path
 | 
			
		||||
            d="M19,10H18V7A6,6,0,0,0,6,7v3H5a3,3,0,0,0-3,3v7a3,3,0,0,0,3,3H19a3,3,0,0,0,3-3V13A3,3,0,0,0,19,10Z"
 | 
			
		||||
            transform="translate(-2 -0.93)"
 | 
			
		||||
            style="fill: #fff;"
 | 
			
		||||
          />
 | 
			
		||||
          <rect x="9.08" y="12.94" width="1.84" height="3.72" />
 | 
			
		||||
          <path
 | 
			
		||||
            d="M19,22.93H5a3,3,0,0,1-3-3v-7a3,3,0,0,1,3-3H19a3,3,0,0,1,3,3v7A3,3,0,0,1,19,22.93Zm-14-11a1,1,0,0,0-1,1v7a1,1,0,0,0,1,1H19a1,1,0,0,0,1-1v-7a1,1,0,0,0-1-1Z"
 | 
			
		||||
            transform="translate(-2 -0.93)"
 | 
			
		||||
          />
 | 
			
		||||
          <path
 | 
			
		||||
            d="M17,11.93a1,1,0,0,1-1-1v-4a4,4,0,0,0-8,0v4a1,1,0,0,1-2,0v-4a6,6,0,0,1,12,0v4A1,1,0,0,1,17,11.93Z"
 | 
			
		||||
            transform="translate(-2 -0.93)"
 | 
			
		||||
          />
 | 
			
		||||
          <rect
 | 
			
		||||
            x="9.58"
 | 
			
		||||
            y="13.36"
 | 
			
		||||
            width="0.84"
 | 
			
		||||
            height="2.72"
 | 
			
		||||
            style="fill: #fff;"
 | 
			
		||||
          />
 | 
			
		||||
          <rect x="9.08" y="12.86" width="1.84" height="3.72" />
 | 
			
		||||
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
 | 
			
		||||
          <path d="M0 0H24V24H0z" style="fill: none;" />
 | 
			
		||||
          <g
 | 
			
		||||
            transform="translate(2 9)"
 | 
			
		||||
            style="stroke-width: 2px; stroke: #4c4c4c; fill: #fff;"
 | 
			
		||||
          >
 | 
			
		||||
            <rect width="20" height="14" style="stroke: none;" rx="2" />
 | 
			
		||||
            <rect
 | 
			
		||||
              width="18"
 | 
			
		||||
              height="12"
 | 
			
		||||
              x="1"
 | 
			
		||||
              y="1"
 | 
			
		||||
              style="fill: none;"
 | 
			
		||||
              rx="1"
 | 
			
		||||
            />
 | 
			
		||||
          </g>
 | 
			
		||||
          <g style="fill: #fff;">
 | 
			
		||||
            <path
 | 
			
		||||
              d="M11 8H1V6c0-2.757 2.243-5 5-5s5 2.243 5 5v2z"
 | 
			
		||||
              style="stroke: none;"
 | 
			
		||||
              transform="translate(6 2)"
 | 
			
		||||
            />
 | 
			
		||||
            <path
 | 
			
		||||
              d="M10 7V6c0-2.205-1.794-4-4-4-2.205 0-4 1.795-4 4v1h8m1.917 2H.083C.028 8.67 0 8.332 0 8V6c0-3.308 2.692-6 6-6s6 2.692 6 6v2c0 .335-.028.67-.083.998V9z"
 | 
			
		||||
              style="stroke: none; fill: #4c4c4c;"
 | 
			
		||||
              transform="translate(6 2)"
 | 
			
		||||
            />
 | 
			
		||||
          </g>
 | 
			
		||||
          <g
 | 
			
		||||
            transform="translate(10 14)"
 | 
			
		||||
            style="fill: #4c4c4c; stroke: #4c4c4c;"
 | 
			
		||||
          >
 | 
			
		||||
            <circle cx="2" cy="2" r="2" style="stroke: none;" />
 | 
			
		||||
            <circle cx="2" cy="2" r="1.5" style="fill: none;" />
 | 
			
		||||
          </g>
 | 
			
		||||
        </svg>
 | 
			
		||||
      </span>
 | 
			
		||||
      <mat-form-field>
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@ucap/ng-ui-chat",
 | 
			
		||||
  "version": "0.0.9",
 | 
			
		||||
  "version": "0.0.12",
 | 
			
		||||
  "publishConfig": {
 | 
			
		||||
    "registry": "https://nexus.loafle.net/repository/npm-ucap/"
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
@ -107,7 +107,7 @@ export class ChatUiRootModule {}
 | 
			
		||||
  providers: [
 | 
			
		||||
    {
 | 
			
		||||
      provide: UCAP_I18N_NAMESPACE,
 | 
			
		||||
      useValue: ['chat']
 | 
			
		||||
      useValue: ['chat', 'common']
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,7 @@
 | 
			
		||||
>
 | 
			
		||||
  <ucap-chat-message-box-attach-file
 | 
			
		||||
    *ngSwitchCase="FileType.File"
 | 
			
		||||
    [fileInfo]="fileInfo"
 | 
			
		||||
    [expired]="getExpiredFile()"
 | 
			
		||||
    (openViewer)="onClickFileViewer(fileInfo)"
 | 
			
		||||
    (save)="onSave($event)"
 | 
			
		||||
@ -13,6 +14,7 @@
 | 
			
		||||
 | 
			
		||||
  <ucap-chat-message-box-attach-file
 | 
			
		||||
    *ngSwitchCase="FileType.Sound"
 | 
			
		||||
    [fileInfo]="fileInfo"
 | 
			
		||||
    [expired]="getExpiredFile()"
 | 
			
		||||
    (openViewer)="onClickFileViewer(fileInfo)"
 | 
			
		||||
    (save)="onSave($event)"
 | 
			
		||||
@ -21,6 +23,7 @@
 | 
			
		||||
 | 
			
		||||
  <ucap-chat-message-box-image
 | 
			
		||||
    *ngSwitchCase="FileType.Image"
 | 
			
		||||
    [fileInfo]="fileInfo"
 | 
			
		||||
    [expired]="getExpiredFile()"
 | 
			
		||||
    (openViewer)="onClickFileViewer(fileInfo)"
 | 
			
		||||
    (save)="onSave($event)"
 | 
			
		||||
@ -28,14 +31,14 @@
 | 
			
		||||
 | 
			
		||||
  <ucap-chat-message-box-video
 | 
			
		||||
    *ngSwitchCase="FileType.Video"
 | 
			
		||||
    [fileInfo]="fileInfo"
 | 
			
		||||
    [expired]="getExpiredFile()"
 | 
			
		||||
    (openViewer)="onClickFileViewer(fileInfo)"
 | 
			
		||||
    (save)="onSave($event)"
 | 
			
		||||
  ></ucap-chat-message-box-video>
 | 
			
		||||
 | 
			
		||||
  <!--
 | 
			
		||||
  <ucap-chat-message-box-text
 | 
			
		||||
    *ngSwitchDefault
 | 
			
		||||
    [message]="message"
 | 
			
		||||
  ></ucap-chat-message-box-text> -->
 | 
			
		||||
  ></ucap-chat-message-box-text>
 | 
			
		||||
</ng-container>
 | 
			
		||||
 | 
			
		||||
@ -1,88 +1,53 @@
 | 
			
		||||
<div class="ucap-chat-message-box-information">
 | 
			
		||||
  <ng-container [ngSwitch]="message.type">
 | 
			
		||||
    <ng-container *ngSwitchCase="EventType.Join">
 | 
			
		||||
      {{ getI18nForSir(getOwnerForJoinEventJson()) }}이
 | 
			
		||||
      {{ getI18nForSir(getInviterForJoinEventJson()) }}을 초대했습니다.
 | 
			
		||||
      <!-- {{
 | 
			
		||||
        'chat.event.inviteToRoomWith'
 | 
			
		||||
          | translate
 | 
			
		||||
      {{
 | 
			
		||||
        'event.inviteToRoomWith'
 | 
			
		||||
          | ucapI18n
 | 
			
		||||
            : {
 | 
			
		||||
                owner: getI18nForSir(message.sentMessageJson.owner),
 | 
			
		||||
                inviter: getI18nForSir(message.sentMessageJson.inviter)
 | 
			
		||||
                owner: getOwnerForJoinEventJson(),
 | 
			
		||||
                inviter: getInviterForJoinEventJson()
 | 
			
		||||
              }
 | 
			
		||||
      }} -->
 | 
			
		||||
      }}
 | 
			
		||||
    </ng-container>
 | 
			
		||||
    <ng-container *ngSwitchCase="EventType.Exit">
 | 
			
		||||
      {{ message.sentMessage }}님이 퇴장하셨습니다.
 | 
			
		||||
      <!-- {{
 | 
			
		||||
        'chat.event.exitFromRoomWith'
 | 
			
		||||
          | translate: { exitor: message.sentMessage }
 | 
			
		||||
      }} -->
 | 
			
		||||
      {{ 'event.exitFromRoomWith' | ucapI18n: { exitor: message.sentMessage } }}
 | 
			
		||||
    </ng-container>
 | 
			
		||||
    <ng-container *ngSwitchCase="EventType.ForcedExit">
 | 
			
		||||
      {{ message.exitForcingRequestUserName }}님이 {{ message.sentMessage }}님을
 | 
			
		||||
      퇴장 시키셨습니다.
 | 
			
		||||
      <!-- {{
 | 
			
		||||
        'chat.event.ejectedFromRoomWith'
 | 
			
		||||
          | translate
 | 
			
		||||
      {{
 | 
			
		||||
        'event.ejectedFromRoomWith'
 | 
			
		||||
          | ucapI18n
 | 
			
		||||
            : {
 | 
			
		||||
                requester: message.exitForcingRequestUserName,
 | 
			
		||||
                ejected: message.sentMessage
 | 
			
		||||
              }
 | 
			
		||||
      }} -->
 | 
			
		||||
      }}
 | 
			
		||||
    </ng-container>
 | 
			
		||||
    <ng-container *ngSwitchCase="EventType.RenameRoom">
 | 
			
		||||
      {{ getRequesterForRenameRoom() }}님이 대화방명을 '{{
 | 
			
		||||
        getRoomNameForRenameRoom()
 | 
			
		||||
      }}'으로 변경하셨습니다.
 | 
			
		||||
      <!-- {{
 | 
			
		||||
        'chat.event.renamedRoomWith'
 | 
			
		||||
          | translate
 | 
			
		||||
      {{
 | 
			
		||||
        'event.renamedRoomWith'
 | 
			
		||||
          | ucapI18n
 | 
			
		||||
            : {
 | 
			
		||||
                requester: message.sentMessageJson.requester,
 | 
			
		||||
                roomName: message.sentMessageJson.roomName
 | 
			
		||||
                requester: getRequesterForRenameRoom(),
 | 
			
		||||
                roomName: getRoomNameForRenameRoom()
 | 
			
		||||
              }
 | 
			
		||||
      }} -->
 | 
			
		||||
      }}
 | 
			
		||||
    </ng-container>
 | 
			
		||||
    <ng-container *ngSwitchCase="EventType.NotificationForTimerRoom">
 | 
			
		||||
      {{ message.sentMessage }}
 | 
			
		||||
    </ng-container>
 | 
			
		||||
    <ng-container *ngSwitchCase="EventType.GuideForRoomTimerChanged">
 | 
			
		||||
      {{ senderName }}님이 타이머를 설정하였습니다. ({{
 | 
			
		||||
        getCalcTimerForGuideForRoomTimerChanged()
 | 
			
		||||
      }})
 | 
			
		||||
      <!-- {{
 | 
			
		||||
        'chat.event.setTimerWith'
 | 
			
		||||
          | translate
 | 
			
		||||
      {{
 | 
			
		||||
        'event.setTimerWith'
 | 
			
		||||
          | ucapI18n
 | 
			
		||||
            : {
 | 
			
		||||
                requester: senderName,
 | 
			
		||||
                timer: getCalcTimer(message.sentMessageJson.time * 1000)
 | 
			
		||||
                timer: getCalcTimerForGuideForRoomTimerChanged()
 | 
			
		||||
              }
 | 
			
		||||
      }} -->
 | 
			
		||||
      }}
 | 
			
		||||
    </ng-container>
 | 
			
		||||
    <ng-container *ngSwitchCase="EventType.NotificationForiOSCapture">
 | 
			
		||||
      {{ message.sentMessage }}님이 대화내용을 캡쳐하였습니다.
 | 
			
		||||
      <!-- {{
 | 
			
		||||
        'chat.event.iosCapture'
 | 
			
		||||
          | translate
 | 
			
		||||
            : {
 | 
			
		||||
                requester: message.sentMessage
 | 
			
		||||
              }
 | 
			
		||||
      }} -->
 | 
			
		||||
      {{ 'event.iosCapture' | ucapI18n: { requester: message.sentMessage } }}
 | 
			
		||||
    </ng-container>
 | 
			
		||||
  </ng-container>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<!-- <div class="ucap-chat-info-event">
 | 
			
		||||
  <div class="info bg-primary-chat">
 | 
			
		||||
    <strong class="text-warn-chat"
 | 
			
		||||
      >김나영, 김준혁,강은정,나정미,박미영,박정은, 박훈, 문영준, 이지은, 이진현,
 | 
			
		||||
      이현준, 임영찬, 임찬우, 정민우,정현욱, 최남진, 최영은, 최진우, 한고은,
 | 
			
		||||
      한정후, 한지민</strong
 | 
			
		||||
    >님이 초대되었습니다.
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <div class="chat-event others bg-accent-chat">
 | 
			
		||||
    자동 삭제 타이머가 10분으로 변경되었습니다.
 | 
			
		||||
  </div>
 | 
			
		||||
</div> -->
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,7 @@ import {
 | 
			
		||||
  GuideForRoomTimerChangedEventJson,
 | 
			
		||||
  JoinEventJson
 | 
			
		||||
} from '@ucap/protocol-event';
 | 
			
		||||
import { TranslateService } from '@ucap/ng-ui-organization';
 | 
			
		||||
import { I18nService } from '@ucap/ng-i18n';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'ucap-chat-message-box-information',
 | 
			
		||||
@ -23,105 +23,64 @@ export class InformationComponent implements OnInit {
 | 
			
		||||
 | 
			
		||||
  EventType = EventType;
 | 
			
		||||
 | 
			
		||||
  constructor(private translateService: TranslateService) {}
 | 
			
		||||
  constructor(private i18nService: I18nService) {}
 | 
			
		||||
 | 
			
		||||
  ngOnInit() {}
 | 
			
		||||
 | 
			
		||||
  getI18nForSir(names: string | string[]) {
 | 
			
		||||
  protected getI18nForSir(names: string | string[]) {
 | 
			
		||||
    if (Array.isArray(names)) {
 | 
			
		||||
      const inviter: string[] = [];
 | 
			
		||||
 | 
			
		||||
      // names.forEach((userName, idx) => {
 | 
			
		||||
      //   inviter.push(
 | 
			
		||||
      //     this.translateService.instant('common.messages.sirWith', {
 | 
			
		||||
      //       sir: userName
 | 
			
		||||
      //     })
 | 
			
		||||
      //   );
 | 
			
		||||
      // });
 | 
			
		||||
      names.forEach((userName, idx) => {
 | 
			
		||||
        inviter.push(userName);
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      return inviter.join(',');
 | 
			
		||||
      return names.join(',');
 | 
			
		||||
    } else {
 | 
			
		||||
      // return this.translateService.instant('common.messages.sirWith', {
 | 
			
		||||
      //   sir: names
 | 
			
		||||
      // });
 | 
			
		||||
      return names;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getOwnerForJoinEventJson() {
 | 
			
		||||
    return (this.message.sentMessageJson as JoinEventJson).owner;
 | 
			
		||||
    return this.getI18nForSir(
 | 
			
		||||
      (this.message.sentMessageJson as JoinEventJson).owner
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
  getInviterForJoinEventJson() {
 | 
			
		||||
    return (this.message.sentMessageJson as JoinEventJson).inviter;
 | 
			
		||||
    return this.getI18nForSir(
 | 
			
		||||
      (this.message.sentMessageJson as JoinEventJson).inviter
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
  getCalcTimerForGuideForRoomTimerChanged() {
 | 
			
		||||
    const millisec =
 | 
			
		||||
      Number(
 | 
			
		||||
        (this.message.sentMessageJson as GuideForRoomTimerChangedEventJson).time
 | 
			
		||||
      ) * 1000;
 | 
			
		||||
    // const langs = this.translateService.instant([
 | 
			
		||||
    //   'common.units.hourFrom',
 | 
			
		||||
    //   'common.units.minute',
 | 
			
		||||
    //   'common.units.second'
 | 
			
		||||
    // ]);
 | 
			
		||||
 | 
			
		||||
    // switch (millisec) {
 | 
			
		||||
    //   case 5000:
 | 
			
		||||
    //     return `5 ${langs['common.units.second']}`;
 | 
			
		||||
    //   case 10000:
 | 
			
		||||
    //     return `10 ${langs['common.units.second']}`;
 | 
			
		||||
    //   case 30000:
 | 
			
		||||
    //     return `30 ${langs['common.units.second']}`;
 | 
			
		||||
    //   case 60000:
 | 
			
		||||
    //     return `1 ${langs['common.units.minute']}`;
 | 
			
		||||
    //   case 300000:
 | 
			
		||||
    //     return `5 ${langs['common.units.minute']}`;
 | 
			
		||||
    //   case 600000:
 | 
			
		||||
    //     return `10 ${langs['common.units.minute']}`;
 | 
			
		||||
    //   case 1800000:
 | 
			
		||||
    //     return `30 ${langs['common.units.minute']}`;
 | 
			
		||||
    //   case 3600000:
 | 
			
		||||
    //     return `1 ${langs['common.units.hourFrom']}`;
 | 
			
		||||
    //   case 21600000:
 | 
			
		||||
    //     return `6 ${langs['common.units.hourFrom']}`;
 | 
			
		||||
    //   case 43200000:
 | 
			
		||||
    //     return `12 ${langs['common.units.hourFrom']}`;
 | 
			
		||||
    //   case 86400000:
 | 
			
		||||
    //     return `24 ${langs['common.units.hourFrom']}`;
 | 
			
		||||
    //   default:
 | 
			
		||||
    //     return `0 ${langs['common.units.second']}`;
 | 
			
		||||
    // }
 | 
			
		||||
 | 
			
		||||
    const langs = ['초', '분', '시간'];
 | 
			
		||||
    const langs = this.i18nService.t([
 | 
			
		||||
      'common.units.hourFrom',
 | 
			
		||||
      'common.units.minute',
 | 
			
		||||
      'common.units.second'
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    switch (millisec) {
 | 
			
		||||
      case 5000:
 | 
			
		||||
        return `5 ${langs[0]}`;
 | 
			
		||||
        return `5 ${langs['common.units.second']}`;
 | 
			
		||||
      case 10000:
 | 
			
		||||
        return `10 ${langs[0]}`;
 | 
			
		||||
        return `10 ${langs['common.units.second']}`;
 | 
			
		||||
      case 30000:
 | 
			
		||||
        return `30 ${langs[0]}`;
 | 
			
		||||
        return `30 ${langs['common.units.second']}`;
 | 
			
		||||
      case 60000:
 | 
			
		||||
        return `1 ${langs[1]}`;
 | 
			
		||||
        return `1 ${langs['common.units.minute']}`;
 | 
			
		||||
      case 300000:
 | 
			
		||||
        return `5 ${langs[1]}`;
 | 
			
		||||
        return `5 ${langs['common.units.minute']}`;
 | 
			
		||||
      case 600000:
 | 
			
		||||
        return `10 ${langs[1]}`;
 | 
			
		||||
        return `10 ${langs['common.units.minute']}`;
 | 
			
		||||
      case 1800000:
 | 
			
		||||
        return `30 ${langs[1]}`;
 | 
			
		||||
        return `30 ${langs['common.units.minute']}`;
 | 
			
		||||
      case 3600000:
 | 
			
		||||
        return `1 ${langs[2]}`;
 | 
			
		||||
        return `1 ${langs['common.units.hourFrom']}`;
 | 
			
		||||
      case 21600000:
 | 
			
		||||
        return `6 ${langs[2]}`;
 | 
			
		||||
        return `6 ${langs['common.units.hourFrom']}`;
 | 
			
		||||
      case 43200000:
 | 
			
		||||
        return `12 ${langs[2]}`;
 | 
			
		||||
        return `12 ${langs['common.units.hourFrom']}`;
 | 
			
		||||
      case 86400000:
 | 
			
		||||
        return `24 ${langs[2]}`;
 | 
			
		||||
        return `24 ${langs['common.units.hourFrom']}`;
 | 
			
		||||
      default:
 | 
			
		||||
        return `0 ${langs[0]}`;
 | 
			
		||||
        return `0 ${langs['common.units.second']}`;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,10 @@
 | 
			
		||||
<div class="ucap-chat-message-box-sticker">
 | 
			
		||||
  <ul>
 | 
			
		||||
    <li *ngIf="stickerUrl">
 | 
			
		||||
      <img [src]="stickerUrl" />
 | 
			
		||||
    <li>
 | 
			
		||||
      <ng-content
 | 
			
		||||
        select="[ucapUiChatStickerComponent='stickerImage']"
 | 
			
		||||
      ></ng-content>
 | 
			
		||||
      <!-- <img [src]="stickerUrl" /> -->
 | 
			
		||||
    </li>
 | 
			
		||||
    <li
 | 
			
		||||
      *ngIf="contents"
 | 
			
		||||
 | 
			
		||||
@ -18,19 +18,23 @@ export class StickerComponent implements OnInit, AfterViewInit {
 | 
			
		||||
  @Input()
 | 
			
		||||
  message: Info<StickerEventJson>;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  stickerUrl?: string;
 | 
			
		||||
  // @Input()
 | 
			
		||||
  // stickerImageRoot: string;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  stickerDefaultImagePath: string;
 | 
			
		||||
  // @Input()
 | 
			
		||||
  // stickerDefaultImage: string;
 | 
			
		||||
 | 
			
		||||
  @Output()
 | 
			
		||||
  openLink = new EventEmitter<string>();
 | 
			
		||||
 | 
			
		||||
  // stickerUrl?: string;
 | 
			
		||||
  contents: string;
 | 
			
		||||
  constructor(private elementRef: ElementRef) {}
 | 
			
		||||
 | 
			
		||||
  ngOnInit() {
 | 
			
		||||
    // if (!!this.message.sentMessageJson.file) {
 | 
			
		||||
    //   this.stickerUrl = `assets/sticker/sticker_s_${this.message.sentMessageJson.file}.png`;
 | 
			
		||||
    // }
 | 
			
		||||
    if (!!this.message.sentMessageJson?.chat) {
 | 
			
		||||
      this.contents = this.message.sentMessageJson.chat;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@ucap/ng-ui-organization",
 | 
			
		||||
  "version": "0.0.55",
 | 
			
		||||
  "version": "0.0.83",
 | 
			
		||||
  "publishConfig": {
 | 
			
		||||
    "registry": "https://nexus.loafle.net/repository/npm-ucap/"
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,8 @@
 | 
			
		||||
@import '~@ucap/ng-ui-material/material';
 | 
			
		||||
 | 
			
		||||
/// var
 | 
			
		||||
/// --ucap-organization-profile-list-item-01-size: 70px
 | 
			
		||||
 | 
			
		||||
.ucap-organization-profile-list-item-01-container {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
@ -23,6 +26,11 @@
 | 
			
		||||
    flex-grow: 1.07;
 | 
			
		||||
    padding-left: 17px;
 | 
			
		||||
 | 
			
		||||
    .profile-image {
 | 
			
		||||
      width: var(--ucap-organization-profile-list-item-01-size);
 | 
			
		||||
      height: var(--ucap-organization-profile-list-item-01-size);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .user-info {
 | 
			
		||||
      display: flex;
 | 
			
		||||
      flex-direction: column;
 | 
			
		||||
@ -37,7 +45,7 @@
 | 
			
		||||
        height: 22px;
 | 
			
		||||
 | 
			
		||||
        .user-name {
 | 
			
		||||
          // @include ellipsis-column(1);
 | 
			
		||||
          @include ellipsis-column(1);
 | 
			
		||||
          height: 22px;
 | 
			
		||||
          font: {
 | 
			
		||||
            size: 14px;
 | 
			
		||||
@ -49,7 +57,7 @@
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .user-grade {
 | 
			
		||||
          // @include ellipsis(1);
 | 
			
		||||
          @include ellipsis(1);
 | 
			
		||||
          align-self: stretch;
 | 
			
		||||
          font: {
 | 
			
		||||
            size: 13px;
 | 
			
		||||
@ -62,7 +70,7 @@
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .dept-name {
 | 
			
		||||
        // @include ellipsis(1);
 | 
			
		||||
        @include ellipsis(1);
 | 
			
		||||
        font: {
 | 
			
		||||
          size: 12px;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -36,7 +36,7 @@ export class ProfileListItem01Component implements OnInit, OnDestroy {
 | 
			
		||||
 | 
			
		||||
  @Output()
 | 
			
		||||
  changeCheck = new EventEmitter<{
 | 
			
		||||
    isChecked: boolean;
 | 
			
		||||
    checked: boolean;
 | 
			
		||||
    userInfo: UserInfoSS;
 | 
			
		||||
  }>();
 | 
			
		||||
 | 
			
		||||
@ -62,9 +62,9 @@ export class ProfileListItem01Component implements OnInit, OnDestroy {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onChangeCheck(isChecked: boolean): void {
 | 
			
		||||
  onChangeCheck(checked: boolean): void {
 | 
			
		||||
    this.changeCheck.emit({
 | 
			
		||||
      isChecked,
 | 
			
		||||
      checked,
 | 
			
		||||
      userInfo: this.userInfo
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,41 @@
 | 
			
		||||
<div class="ucap-organization-profile-list-item-01-container">
 | 
			
		||||
  <div class="user-profile-info">
 | 
			
		||||
    <div class="profile-image">
 | 
			
		||||
      <ng-content
 | 
			
		||||
        select="[ucapOrganizationProfileListItem01='profileImage']"
 | 
			
		||||
      ></ng-content>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="user-info">
 | 
			
		||||
      <div class="user-n-g">
 | 
			
		||||
        <div class="user-name">
 | 
			
		||||
          {{ userInfo | ucapOrganizationTranslate: 'name' }}
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="user-grade">
 | 
			
		||||
          {{ userInfo | ucapOrganizationTranslate: 'grade' }}
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="dept-name">
 | 
			
		||||
        {{ userInfo | ucapOrganizationTranslate: 'deptName' }}
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="user-info">
 | 
			
		||||
    <ng-content
 | 
			
		||||
      class="user-info-content"
 | 
			
		||||
      select="[appProfileListItemUserInfo='info']"
 | 
			
		||||
    ></ng-content>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="user-action">
 | 
			
		||||
    <ng-content
 | 
			
		||||
      class="user-action-content"
 | 
			
		||||
      select="[appProfileListItemUserAction='action']"
 | 
			
		||||
    ></ng-content>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div *ngIf="checkable">
 | 
			
		||||
    <mat-checkbox
 | 
			
		||||
      #checkbox
 | 
			
		||||
      [checked]="checked"
 | 
			
		||||
      (change)="onChangeCheck(checkbox.checked)"
 | 
			
		||||
    ></mat-checkbox>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
@ -0,0 +1,113 @@
 | 
			
		||||
@import '~@ucap/ng-ui-material/material';
 | 
			
		||||
 | 
			
		||||
/// var
 | 
			
		||||
/// --ucap-organization-profile-list-item-01-size: 70px
 | 
			
		||||
 | 
			
		||||
.ucap-organization-profile-list-item-01-container {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-flow: row nowrap;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
  padding: 0;
 | 
			
		||||
  height: 70px;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  &.line-top {
 | 
			
		||||
    border-top: 1px solid #cccccc;
 | 
			
		||||
  }
 | 
			
		||||
  &.line-bottom {
 | 
			
		||||
    border-bottom: 1px solid #cccccc;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .user-profile-info {
 | 
			
		||||
    display: inline-flex;
 | 
			
		||||
    flex-direction: row;
 | 
			
		||||
    flex-grow: 1.07;
 | 
			
		||||
    padding-left: 17px;
 | 
			
		||||
 | 
			
		||||
    .profile-image {
 | 
			
		||||
      width: var(--ucap-organization-profile-list-item-01-size);
 | 
			
		||||
      height: var(--ucap-organization-profile-list-item-01-size);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .user-info {
 | 
			
		||||
      display: flex;
 | 
			
		||||
      flex-direction: column;
 | 
			
		||||
      align-items: flex-start;
 | 
			
		||||
      justify-content: flex-start;
 | 
			
		||||
      padding-left: 16px;
 | 
			
		||||
 | 
			
		||||
      .user-n-g {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        flex-flow: row-reverse nowrap;
 | 
			
		||||
        align-items: flex-end;
 | 
			
		||||
        height: 22px;
 | 
			
		||||
 | 
			
		||||
        .user-name {
 | 
			
		||||
          @include ellipsis-column(1);
 | 
			
		||||
          height: 22px;
 | 
			
		||||
          font: {
 | 
			
		||||
            size: 14px;
 | 
			
		||||
            weight: 600;
 | 
			
		||||
          }
 | 
			
		||||
          color: #212121;
 | 
			
		||||
          order: 1;
 | 
			
		||||
          -ms-flex-order: 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .user-grade {
 | 
			
		||||
          @include ellipsis(1);
 | 
			
		||||
          align-self: stretch;
 | 
			
		||||
          font: {
 | 
			
		||||
            size: 13px;
 | 
			
		||||
          }
 | 
			
		||||
          color: #707070;
 | 
			
		||||
          margin-left: 4px;
 | 
			
		||||
          order: 0;
 | 
			
		||||
          -ms-flex-order: 0;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .dept-name {
 | 
			
		||||
        @include ellipsis(1);
 | 
			
		||||
        font: {
 | 
			
		||||
          size: 12px;
 | 
			
		||||
        }
 | 
			
		||||
        color: #666666;
 | 
			
		||||
        line-height: 16px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .company-info {
 | 
			
		||||
    flex-grow: 1.4;
 | 
			
		||||
    padding-left: 16px;
 | 
			
		||||
    position: relative;
 | 
			
		||||
    font: {
 | 
			
		||||
      size: 14px;
 | 
			
		||||
    }
 | 
			
		||||
    color: #333333;
 | 
			
		||||
    &:before {
 | 
			
		||||
      content: '';
 | 
			
		||||
      width: 1px;
 | 
			
		||||
      height: 36px;
 | 
			
		||||
      position: absolute;
 | 
			
		||||
      left: 0;
 | 
			
		||||
      top: calc(50% - 18px);
 | 
			
		||||
      border-left: 1px solid #cccccc;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .contact {
 | 
			
		||||
    flex-grow: 1;
 | 
			
		||||
    font: {
 | 
			
		||||
      size: 14px;
 | 
			
		||||
    }
 | 
			
		||||
    color: #333333;
 | 
			
		||||
  }
 | 
			
		||||
  .chk-box {
 | 
			
		||||
    flex: 0 0 56px;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,25 @@
 | 
			
		||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
 | 
			
		||||
import { By } from '@angular/platform-browser';
 | 
			
		||||
import { DebugElement } from '@angular/core';
 | 
			
		||||
import { ProfileListItem01Component } from './profile-list-item-01.component';
 | 
			
		||||
 | 
			
		||||
describe('ucap::ui-organization::ProfileListItem01Component', () => {
 | 
			
		||||
  let component: ProfileListItem01Component;
 | 
			
		||||
  let fixture: ComponentFixture<ProfileListItem01Component>;
 | 
			
		||||
 | 
			
		||||
  beforeEach(async(() => {
 | 
			
		||||
    TestBed.configureTestingModule({
 | 
			
		||||
      declarations: [ProfileListItem01Component]
 | 
			
		||||
    }).compileComponents();
 | 
			
		||||
  }));
 | 
			
		||||
 | 
			
		||||
  beforeEach(() => {
 | 
			
		||||
    fixture = TestBed.createComponent(ProfileListItem01Component);
 | 
			
		||||
    component = fixture.componentInstance;
 | 
			
		||||
    fixture.detectChanges();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should create', () => {
 | 
			
		||||
    expect(component).toBeTruthy();
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
@ -0,0 +1,68 @@
 | 
			
		||||
import { moduleMetadata } from '@storybook/angular';
 | 
			
		||||
import { action } from '@storybook/addon-actions';
 | 
			
		||||
import { linkTo } from '@storybook/addon-links';
 | 
			
		||||
 | 
			
		||||
import { BrowserModule } from '@angular/platform-browser';
 | 
			
		||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
 | 
			
		||||
 | 
			
		||||
import { UserInfoF } from '@ucap/protocol-query';
 | 
			
		||||
 | 
			
		||||
import { OrganizationUiModule } from '../organization-ui.module';
 | 
			
		||||
 | 
			
		||||
import { ProfileListItem02Component } from './profile-list-item-02.component';
 | 
			
		||||
import { RoleCode } from '@ucap/protocol-authentication';
 | 
			
		||||
import { CallMode, EmployeeType } from '@ucap/core';
 | 
			
		||||
 | 
			
		||||
const userInfo: UserInfoF = {
 | 
			
		||||
  seq: 1234,
 | 
			
		||||
  name: '사용자1',
 | 
			
		||||
  profileImageFile: '사진파일',
 | 
			
		||||
  grade: '직급',
 | 
			
		||||
  intro: '업무소개',
 | 
			
		||||
  companyCode: '기관코드',
 | 
			
		||||
  hpNumber: '핸드폰번호',
 | 
			
		||||
  lineNumber: '내선번호',
 | 
			
		||||
  email: '이메일',
 | 
			
		||||
  isMobile: true,
 | 
			
		||||
  isBuddy: true,
 | 
			
		||||
  isFavorit: true,
 | 
			
		||||
  /**  */
 | 
			
		||||
  deptName: '부서명',
 | 
			
		||||
  /**  */
 | 
			
		||||
  order: '조회순서',
 | 
			
		||||
 | 
			
		||||
  isActive: true,
 | 
			
		||||
  roleCd: RoleCode.Self,
 | 
			
		||||
  employeeNum: 'A34567',
 | 
			
		||||
  madn: 'MADN',
 | 
			
		||||
  hardSadn: 'HARDPHONE_SADN',
 | 
			
		||||
  fmcSadn: 'FMC_SADN',
 | 
			
		||||
  nickName: 'nickName',
 | 
			
		||||
  nameEn: '사용자명(영어)',
 | 
			
		||||
  nameCn: '사용자명(중국어)',
 | 
			
		||||
  gradeEn: '직급(영어)',
 | 
			
		||||
  gradeCn: '직급(중국어)',
 | 
			
		||||
  deptNameEn: '부서명(영어)',
 | 
			
		||||
  deptNameCn: '부서명(중국어)',
 | 
			
		||||
  isPrivacyAgree: true,
 | 
			
		||||
  isValidLogin: true,
 | 
			
		||||
  employeeType: EmployeeType.Regular
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  title: 'ui-organization::ProfileListItem02Component',
 | 
			
		||||
  component: ProfileListItem02Component,
 | 
			
		||||
  decorators: [
 | 
			
		||||
    moduleMetadata({
 | 
			
		||||
      imports: [BrowserModule, BrowserAnimationsModule, OrganizationUiModule],
 | 
			
		||||
      providers: []
 | 
			
		||||
    })
 | 
			
		||||
  ]
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const Default = () => ({
 | 
			
		||||
  component: ProfileListItem02Component,
 | 
			
		||||
  props: {
 | 
			
		||||
    userInfo
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
@ -0,0 +1,24 @@
 | 
			
		||||
@import '~@ucap/ng-ui-material/material';
 | 
			
		||||
 | 
			
		||||
@mixin ucap-organization-profile-list-item-01-theme($theme) {
 | 
			
		||||
  $is-dark-theme: map-get($theme, is-dark);
 | 
			
		||||
  $primary: map-get($theme, primary);
 | 
			
		||||
  $accent: map-get($theme, accent);
 | 
			
		||||
  $warn: map-get($theme, warn);
 | 
			
		||||
  $background: map-get($theme, background);
 | 
			
		||||
  $foreground: map-get($theme, foreground);
 | 
			
		||||
 | 
			
		||||
  .ucap-organization-profile-list-item-01-container {
 | 
			
		||||
    border-color: mat-color($foreground, secondary-text);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@mixin ucap-organization-profile-list-item-01-typography($config) {
 | 
			
		||||
  .ucap-organization-profile-list-item-01-container {
 | 
			
		||||
    .searchword-container {
 | 
			
		||||
      .form-field-input-searchword {
 | 
			
		||||
        font-family: mat-font-family($config);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,62 @@
 | 
			
		||||
import { Subject } from 'rxjs';
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
  Component,
 | 
			
		||||
  OnInit,
 | 
			
		||||
  OnDestroy,
 | 
			
		||||
  ChangeDetectionStrategy,
 | 
			
		||||
  ChangeDetectorRef,
 | 
			
		||||
  Input,
 | 
			
		||||
  Output,
 | 
			
		||||
  EventEmitter
 | 
			
		||||
} from '@angular/core';
 | 
			
		||||
 | 
			
		||||
import { UserInfoF } from '@ucap/protocol-query';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'ucap-organization-profile-list-item-02',
 | 
			
		||||
  templateUrl: './profile-list-item-02.component.html',
 | 
			
		||||
  styleUrls: ['./profile-list-item-02.component.scss'],
 | 
			
		||||
  changeDetection: ChangeDetectionStrategy.OnPush
 | 
			
		||||
})
 | 
			
		||||
export class ProfileListItem02Component implements OnInit, OnDestroy {
 | 
			
		||||
  @Input()
 | 
			
		||||
  userInfo: UserInfoF;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  authCall = false;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  checkable = true;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  checked = false;
 | 
			
		||||
 | 
			
		||||
  @Output()
 | 
			
		||||
  changeCheck = new EventEmitter<{
 | 
			
		||||
    checked: boolean;
 | 
			
		||||
    userInfo: UserInfoF;
 | 
			
		||||
  }>();
 | 
			
		||||
 | 
			
		||||
  private ngOnDestroySubject: Subject<void>;
 | 
			
		||||
 | 
			
		||||
  constructor(private changeDetectorRef: ChangeDetectorRef) {}
 | 
			
		||||
 | 
			
		||||
  ngOnInit(): void {
 | 
			
		||||
    this.ngOnDestroySubject = new Subject();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ngOnDestroy(): void {
 | 
			
		||||
    if (!!this.ngOnDestroySubject) {
 | 
			
		||||
      this.ngOnDestroySubject.next();
 | 
			
		||||
      this.ngOnDestroySubject.complete();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onChangeCheck(checked: boolean): void {
 | 
			
		||||
    this.changeCheck.emit({
 | 
			
		||||
      checked,
 | 
			
		||||
      userInfo: this.userInfo
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
<div class="ucap-organization-profile-list-container">
 | 
			
		||||
<div class="ucap-organization-profile-list-container" fxFlexFill>
 | 
			
		||||
  <cdk-virtual-scroll-viewport #cvsvList perfectScrollbar fxFlexFill>
 | 
			
		||||
    <ng-container *cdkVirtualFor="let userInfo of userInfos">
 | 
			
		||||
      <ng-container
 | 
			
		||||
 | 
			
		||||
@ -1,27 +1,31 @@
 | 
			
		||||
<div class="ucap-organization-profile-selection-01-container">
 | 
			
		||||
  <div class="ucap-organization-profile-selection-01-body">
 | 
			
		||||
<div class="ucap-organization-profile-selection-01-container" fxLayout="column">
 | 
			
		||||
  <div
 | 
			
		||||
    *ngIf="!!headerTemplate"
 | 
			
		||||
    class="ucap-organization-profile-selection-01-header"
 | 
			
		||||
    fxFlex="0 0 48px"
 | 
			
		||||
  >
 | 
			
		||||
    <ng-container [ngTemplateOutlet]="headerTemplate"></ng-container>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="ucap-organization-profile-selection-01-body" fxFlex="1 1 auto">
 | 
			
		||||
    <mat-chip-list aria-label="User selection" perfectScrollbar>
 | 
			
		||||
      <mat-chip
 | 
			
		||||
        *ngFor="let profileSelection of _profileSelectionList"
 | 
			
		||||
        [color]="profileSelection.color"
 | 
			
		||||
        [selectable]="profileSelection.selectable"
 | 
			
		||||
        [selected]="profileSelection.selected"
 | 
			
		||||
        [removable]="profileSelection.removable"
 | 
			
		||||
        (selectionChange)="
 | 
			
		||||
          _onSelectionChange($event, profileSelection.userInfo)
 | 
			
		||||
        "
 | 
			
		||||
        (removed)="_onRemoved($event, profileSelection.userInfo)"
 | 
			
		||||
        *ngFor="let userInfo of _userInfoList"
 | 
			
		||||
        [color]="_colorFor(userInfo)"
 | 
			
		||||
        [removable]="_removableFor(userInfo)"
 | 
			
		||||
        (removed)="_onRemoved($event, userInfo)"
 | 
			
		||||
      >
 | 
			
		||||
        {{ profileSelection.userInfo.name }}
 | 
			
		||||
        <mat-icon matChipRemove *ngIf="profileSelection.removable">
 | 
			
		||||
        {{ userInfo.name }}
 | 
			
		||||
        <mat-icon matChipRemove *ngIf="removableFor(userInfo)">
 | 
			
		||||
          clear
 | 
			
		||||
        </mat-icon>
 | 
			
		||||
      </mat-chip>
 | 
			
		||||
    </mat-chip-list>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="ucap-organization-profile-selection-01-actions">
 | 
			
		||||
    <ng-content
 | 
			
		||||
      select="[ucapOrganizationSelectedProfileList01='action']"
 | 
			
		||||
    ></ng-content>
 | 
			
		||||
  <div
 | 
			
		||||
    *ngIf="!!actionsTemplate"
 | 
			
		||||
    class="ucap-organization-profile-selection-01-actions"
 | 
			
		||||
    fxFlex="0 0 60px"
 | 
			
		||||
  >
 | 
			
		||||
    <ng-container [ngTemplateOutlet]="actionsTemplate"></ng-container>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
@ -3,4 +3,9 @@
 | 
			
		||||
.ucap-organization-profile-selection-01-container {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
 | 
			
		||||
  .ucap-organization-profile-selection-01-body {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: 100%;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -7,11 +7,15 @@ import {
 | 
			
		||||
  ChangeDetectionStrategy,
 | 
			
		||||
  ChangeDetectorRef,
 | 
			
		||||
  Output,
 | 
			
		||||
  EventEmitter
 | 
			
		||||
  EventEmitter,
 | 
			
		||||
  Input,
 | 
			
		||||
  Directive,
 | 
			
		||||
  ContentChild,
 | 
			
		||||
  TemplateRef
 | 
			
		||||
} from '@angular/core';
 | 
			
		||||
 | 
			
		||||
import { UserInfo } from '@ucap/protocol-sync';
 | 
			
		||||
import { MatChipSelectionChange, MatChipEvent } from '@angular/material/chips';
 | 
			
		||||
import { MatChipEvent } from '@angular/material/chips';
 | 
			
		||||
 | 
			
		||||
export interface ProfileSelection {
 | 
			
		||||
  userInfo: UserInfo;
 | 
			
		||||
@ -21,6 +25,16 @@ export interface ProfileSelection {
 | 
			
		||||
  removable?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Directive({
 | 
			
		||||
  selector: '[ucapOrganizationProfileSelection01Header]'
 | 
			
		||||
})
 | 
			
		||||
export class ProfileSelection01HeaderDirective {}
 | 
			
		||||
 | 
			
		||||
@Directive({
 | 
			
		||||
  selector: '[ucapOrganizationProfileSelection01Actions]'
 | 
			
		||||
})
 | 
			
		||||
export class ProfileSelection01ActionsDirective {}
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'ucap-organization-profile-selection-01',
 | 
			
		||||
  templateUrl: './profile-selection-01.component.html',
 | 
			
		||||
@ -28,17 +42,34 @@ export interface ProfileSelection {
 | 
			
		||||
  changeDetection: ChangeDetectionStrategy.OnPush
 | 
			
		||||
})
 | 
			
		||||
export class ProfileSelection01Component implements OnInit, OnDestroy {
 | 
			
		||||
  @Output()
 | 
			
		||||
  selectionChange: EventEmitter<{
 | 
			
		||||
    selected: boolean;
 | 
			
		||||
    userInfo: UserInfo;
 | 
			
		||||
  }> = new EventEmitter();
 | 
			
		||||
  @Input()
 | 
			
		||||
  set userInfoList(value: UserInfo[]) {
 | 
			
		||||
    console.log('userInfoList', value);
 | 
			
		||||
    this._userInfoList = value;
 | 
			
		||||
  }
 | 
			
		||||
  // tslint:disable-next-line: variable-name
 | 
			
		||||
  _userInfoList: UserInfo[];
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  removableFor: (userInfo: UserInfo) => boolean;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  colorFor: (userInfo: UserInfo) => string;
 | 
			
		||||
 | 
			
		||||
  @Output()
 | 
			
		||||
  removed: EventEmitter<UserInfo> = new EventEmitter();
 | 
			
		||||
 | 
			
		||||
  // tslint:disable-next-line: variable-name
 | 
			
		||||
  _profileSelectionList: ProfileSelection[] = [];
 | 
			
		||||
  @ContentChild(ProfileSelection01HeaderDirective, {
 | 
			
		||||
    read: TemplateRef,
 | 
			
		||||
    static: false
 | 
			
		||||
  })
 | 
			
		||||
  headerTemplate: TemplateRef<ProfileSelection01HeaderDirective>;
 | 
			
		||||
 | 
			
		||||
  @ContentChild(ProfileSelection01ActionsDirective, {
 | 
			
		||||
    read: TemplateRef,
 | 
			
		||||
    static: false
 | 
			
		||||
  })
 | 
			
		||||
  actionsTemplate: TemplateRef<ProfileSelection01ActionsDirective>;
 | 
			
		||||
 | 
			
		||||
  private ngOnDestroySubject: Subject<void>;
 | 
			
		||||
 | 
			
		||||
@ -55,54 +86,21 @@ export class ProfileSelection01Component implements OnInit, OnDestroy {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  addProfileSelection(profileSelectionList: ProfileSelection[]): void {
 | 
			
		||||
    if (!profileSelectionList || 0 === profileSelectionList.length) {
 | 
			
		||||
      return;
 | 
			
		||||
  _colorFor(userInfo: UserInfo): string {
 | 
			
		||||
    if (!this.colorFor) {
 | 
			
		||||
      return undefined;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    profileSelectionList.forEach((v) => {
 | 
			
		||||
      const i = this.indexOfProfileSelection(v);
 | 
			
		||||
      if (-1 === i) {
 | 
			
		||||
        this._profileSelectionList.push(v);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    return this.colorFor(userInfo);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  removeProfileSelection(profileSelectionList: ProfileSelection[]): void {
 | 
			
		||||
    if (!profileSelectionList || 0 === profileSelectionList.length) {
 | 
			
		||||
      return;
 | 
			
		||||
  _removableFor(userInfo: UserInfo): boolean {
 | 
			
		||||
    if (!this.removableFor) {
 | 
			
		||||
      return undefined;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    profileSelectionList.forEach((v) => {
 | 
			
		||||
      const i = this.indexOfProfileSelection(v);
 | 
			
		||||
      if (-1 < i) {
 | 
			
		||||
        this._profileSelectionList.splice(i, 1);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  _onSelectionChange(event: MatChipSelectionChange, userInfo: UserInfo) {
 | 
			
		||||
    this.selectionChange.emit({
 | 
			
		||||
      selected: event.selected,
 | 
			
		||||
      userInfo
 | 
			
		||||
    });
 | 
			
		||||
    return this.removableFor(userInfo);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  _onRemoved(event: MatChipEvent, userInfo: UserInfo) {
 | 
			
		||||
    this.removed.emit(userInfo);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private indexOfProfileSelection(profileSelection: ProfileSelection): number {
 | 
			
		||||
    if (
 | 
			
		||||
      !this._profileSelectionList ||
 | 
			
		||||
      0 === this._profileSelectionList.length ||
 | 
			
		||||
      !profileSelection
 | 
			
		||||
    ) {
 | 
			
		||||
      return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return this._profileSelectionList.findIndex(
 | 
			
		||||
      (v) => v.userInfo.seq === profileSelection.userInfo.seq
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -28,6 +28,7 @@
 | 
			
		||||
        matInput
 | 
			
		||||
        #inputSearchWord
 | 
			
		||||
        [placeholder]="placeholder"
 | 
			
		||||
        [value]="!!defaultSearchWord ? defaultSearchWord : ''"
 | 
			
		||||
        (keyup.enter)="onKeyupEnter($event)"
 | 
			
		||||
      />
 | 
			
		||||
      <button
 | 
			
		||||
 | 
			
		||||
@ -14,8 +14,8 @@
 | 
			
		||||
  display: flex;
 | 
			
		||||
 | 
			
		||||
  border: {
 | 
			
		||||
    width: var(--ucap-organization-search-for-tenant-border-width, 1px);
 | 
			
		||||
    color: var(--ucap-organization-search-for-tenant-border-color, #e42f66);
 | 
			
		||||
    width: var(--ucap-organization-search-for-tenant-border-width);
 | 
			
		||||
    color: var(--ucap-organization-search-for-tenant-border-color);
 | 
			
		||||
    style: solid;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -23,7 +23,6 @@ export default {
 | 
			
		||||
export const Default = () => ({
 | 
			
		||||
  component: SearchForTenantComponent,
 | 
			
		||||
  props: {
 | 
			
		||||
    text: 'Hello SearchForTenantComponent',
 | 
			
		||||
    companyList: [
 | 
			
		||||
      {
 | 
			
		||||
        companyCode: 'CD1',
 | 
			
		||||
 | 
			
		||||
@ -29,6 +29,9 @@ export class SearchForTenantComponent implements OnInit, OnDestroy {
 | 
			
		||||
  @Input()
 | 
			
		||||
  defaultCompany: string;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  defaultSearchWord: string;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  placeholder: string;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -4,21 +4,25 @@
 | 
			
		||||
      *cdkVirtualFor="let node of dataSource.expandedData$"
 | 
			
		||||
    ></ng-container>
 | 
			
		||||
 | 
			
		||||
    <mat-tree #treeList [dataSource]="dataSource" [treeControl]="treeControl">
 | 
			
		||||
    <mat-tree
 | 
			
		||||
      #treeList
 | 
			
		||||
      [dataSource]="dataSource"
 | 
			
		||||
      [treeControl]="treeControl"
 | 
			
		||||
      [trackBy]="trackBy"
 | 
			
		||||
    >
 | 
			
		||||
      <mat-tree-node
 | 
			
		||||
        *matTreeNodeDef="let node"
 | 
			
		||||
        matTreeNodePadding
 | 
			
		||||
        matTreeNodePaddingIndent="20"
 | 
			
		||||
        class="tree-no-child"
 | 
			
		||||
        (click)="onClickNode($event, node)"
 | 
			
		||||
      >
 | 
			
		||||
        <li
 | 
			
		||||
          (click)="onClickNode(node)"
 | 
			
		||||
          matRipple
 | 
			
		||||
          [ngClass]="
 | 
			
		||||
            currentDeptSeq === node?.data?.deptInfo?.seq ? 'current' : ''
 | 
			
		||||
          "
 | 
			
		||||
        >
 | 
			
		||||
          <div class="tree-node-body">
 | 
			
		||||
          <div matRipple class="tree-node-body">
 | 
			
		||||
            {{ node?.data?.deptInfo | ucapOrganizationTranslate: 'name' }}
 | 
			
		||||
          </div>
 | 
			
		||||
        </li>
 | 
			
		||||
@ -29,9 +33,11 @@
 | 
			
		||||
        matTreeNodePadding
 | 
			
		||||
        matTreeNodePaddingIndent="20"
 | 
			
		||||
        class="tree-has-child"
 | 
			
		||||
        (click)="onClickNode($event, node)"
 | 
			
		||||
      >
 | 
			
		||||
        <li (click)="onClickNode(node)" matRipple>
 | 
			
		||||
        <li>
 | 
			
		||||
          <div
 | 
			
		||||
            matRipple
 | 
			
		||||
            class="tree-node-body"
 | 
			
		||||
            [ngClass]="
 | 
			
		||||
              currentDeptSeq === node?.data?.deptInfo?.seq ? 'current' : ''
 | 
			
		||||
 | 
			
		||||
@ -30,6 +30,7 @@ import { VirtualScrollTreeFlatDataSource } from '@ucap/ng-ui';
 | 
			
		||||
 | 
			
		||||
export interface OrganizationNode {
 | 
			
		||||
  deptInfo: DeptInfo;
 | 
			
		||||
  ancestorSeq?: number;
 | 
			
		||||
  children?: OrganizationNode[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -94,7 +95,9 @@ export class TreeComponent implements OnInit, OnDestroy {
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (nodeMap.has(deptInfo.parentSeq)) {
 | 
			
		||||
        nodeMap.get(deptInfo.parentSeq).children.push(node);
 | 
			
		||||
        const ancestor = nodeMap.get(deptInfo.parentSeq);
 | 
			
		||||
        node.ancestorSeq = ancestor.deptInfo.seq;
 | 
			
		||||
        ancestor.children.push(node);
 | 
			
		||||
      } else {
 | 
			
		||||
        remainChildNodeList.push(node);
 | 
			
		||||
      }
 | 
			
		||||
@ -110,28 +113,32 @@ export class TreeComponent implements OnInit, OnDestroy {
 | 
			
		||||
      rootNodeList = [...rootNodeList[0].children];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this._deptInfoList = deptInfoList;
 | 
			
		||||
 | 
			
		||||
    remainChildNodeList.forEach((node) => {
 | 
			
		||||
      if (nodeMap.has(node.deptInfo.parentSeq)) {
 | 
			
		||||
        nodeMap.get(node.deptInfo.parentSeq).children.push(node);
 | 
			
		||||
      const ancestor = nodeMap.get(node.deptInfo.parentSeq);
 | 
			
		||||
      if (!!ancestor) {
 | 
			
		||||
        node.ancestorSeq = ancestor.deptInfo.seq;
 | 
			
		||||
        ancestor.children.push(node);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    this.dataSource.data = rootNodeList;
 | 
			
		||||
 | 
			
		||||
    if (!!data.expanded) {
 | 
			
		||||
      data.expanded.forEach((s) => {
 | 
			
		||||
        this.expand(s);
 | 
			
		||||
      });
 | 
			
		||||
      this.expand(...data.expanded);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.changeDetectorRef.detectChanges();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  currentDeptSeq: number;
 | 
			
		||||
  @Output() currentDeptSeqChange: EventEmitter<number> = new EventEmitter();
 | 
			
		||||
  @Input() set currentDeptSeq(deptInfoSeq: number) {
 | 
			
		||||
    this._currentDeptSeq = deptInfoSeq;
 | 
			
		||||
  }
 | 
			
		||||
  get currentDeptSeq() {
 | 
			
		||||
    return this._currentDeptSeq;
 | 
			
		||||
  }
 | 
			
		||||
  // tslint:disable-next-line: variable-name
 | 
			
		||||
  _deptInfoList: DeptInfo[];
 | 
			
		||||
  _currentDeptSeq: number;
 | 
			
		||||
 | 
			
		||||
  @Output()
 | 
			
		||||
  clickNode = new EventEmitter<DeptInfo>();
 | 
			
		||||
@ -201,19 +208,32 @@ export class TreeComponent implements OnInit, OnDestroy {
 | 
			
		||||
 | 
			
		||||
  hasChild = (_: number, node: FlatNode) => node.expandable;
 | 
			
		||||
 | 
			
		||||
  onClickNode(node: FlatNode) {
 | 
			
		||||
  trackBy = (_: number, node: FlatNode) => node.data.deptInfo.seq;
 | 
			
		||||
 | 
			
		||||
  onClickNode(event: Event, node: FlatNode) {
 | 
			
		||||
    event.stopPropagation();
 | 
			
		||||
 | 
			
		||||
    this.clickNode.emit(node.data.deptInfo);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  expand(deptSeq: number) {
 | 
			
		||||
    if (!this.treeControl.dataNodes) {
 | 
			
		||||
  expand(...deptSeq: number[]) {
 | 
			
		||||
    if (!this.treeControl.dataNodes || !deptSeq || 0 === deptSeq.length) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    const node = this.treeControl.dataNodes.find(
 | 
			
		||||
      (n) => n.data.deptInfo.seq === deptSeq
 | 
			
		||||
    );
 | 
			
		||||
    if (!!node) {
 | 
			
		||||
      this.treeControl.expand(node);
 | 
			
		||||
    const flatNodes: FlatNode[] = [];
 | 
			
		||||
 | 
			
		||||
    deptSeq.forEach((s) => {
 | 
			
		||||
      const node = this.treeControl.dataNodes.find(
 | 
			
		||||
        (n) => n.data.deptInfo.seq === s
 | 
			
		||||
      );
 | 
			
		||||
      if (!!node) {
 | 
			
		||||
        flatNodes.push(node);
 | 
			
		||||
        this.selectHierarchy(flatNodes, node);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    if (0 < flatNodes.length) {
 | 
			
		||||
      this.treeControl.expansionModel.select(...flatNodes);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -236,4 +256,30 @@ export class TreeComponent implements OnInit, OnDestroy {
 | 
			
		||||
  collapseAll() {
 | 
			
		||||
    this.treeControl.collapseAll();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private selectHierarchy(flatNodes: FlatNode[], flatNode: FlatNode): void {
 | 
			
		||||
    // tslint:disable-next-line: variable-name
 | 
			
		||||
    let _flatNode = flatNode;
 | 
			
		||||
    while (true) {
 | 
			
		||||
      if (!_flatNode) {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      const ancestorSeq = _flatNode.data.ancestorSeq;
 | 
			
		||||
      if (!ancestorSeq) {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      _flatNode = this.treeControl.dataNodes.find(
 | 
			
		||||
        (n) => n.data.deptInfo.seq === ancestorSeq
 | 
			
		||||
      );
 | 
			
		||||
      if (!_flatNode) {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      const i = flatNodes.findIndex(
 | 
			
		||||
        (n) => n.data.deptInfo.seq === _flatNode.data.deptInfo.seq
 | 
			
		||||
      );
 | 
			
		||||
      if (-1 === i) {
 | 
			
		||||
        flatNodes.push(_flatNode);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -25,12 +25,17 @@ import { _MODULE_CONFIG } from './config/token';
 | 
			
		||||
 | 
			
		||||
import { Profile01Component } from './components/profile-01.component';
 | 
			
		||||
import { ProfileListItem01Component } from './components/profile-list-item-01.component';
 | 
			
		||||
import { ProfileListItem02Component } from './components/profile-list-item-02.component';
 | 
			
		||||
import { ProfileImage01Component } from './components/profile-image-01.component';
 | 
			
		||||
import {
 | 
			
		||||
  ProfileListComponent,
 | 
			
		||||
  ProfileListNodeDirective
 | 
			
		||||
} from './components/profile-list.component';
 | 
			
		||||
import { ProfileSelection01Component } from './components/profile-selection-01.component';
 | 
			
		||||
import {
 | 
			
		||||
  ProfileSelection01Component,
 | 
			
		||||
  ProfileSelection01HeaderDirective,
 | 
			
		||||
  ProfileSelection01ActionsDirective
 | 
			
		||||
} from './components/profile-selection-01.component';
 | 
			
		||||
import { SearchForTenantComponent } from './components/search-for-tenant.component';
 | 
			
		||||
import { TreeComponent } from './components/tree.component';
 | 
			
		||||
 | 
			
		||||
@ -42,6 +47,7 @@ import { UCAP_I18N_NAMESPACE, I18nModule } from '@ucap/ng-i18n';
 | 
			
		||||
const COMPONENTS = [
 | 
			
		||||
  Profile01Component,
 | 
			
		||||
  ProfileListItem01Component,
 | 
			
		||||
  ProfileListItem02Component,
 | 
			
		||||
  ProfileListComponent,
 | 
			
		||||
  ProfileImage01Component,
 | 
			
		||||
  ProfileSelection01Component,
 | 
			
		||||
@ -50,7 +56,11 @@ const COMPONENTS = [
 | 
			
		||||
];
 | 
			
		||||
const DIALOGS = [];
 | 
			
		||||
const PIPES = [TranslatePipe];
 | 
			
		||||
const DIRECTIVES = [ProfileListNodeDirective];
 | 
			
		||||
const DIRECTIVES = [
 | 
			
		||||
  ProfileListNodeDirective,
 | 
			
		||||
  ProfileSelection01HeaderDirective,
 | 
			
		||||
  ProfileSelection01ActionsDirective
 | 
			
		||||
];
 | 
			
		||||
const SERVICES = [TranslateService];
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
 | 
			
		||||
@ -163,7 +163,7 @@ export class PresenceUtil {
 | 
			
		||||
        return statusBulkInfo.phoneStatus;
 | 
			
		||||
      case PresenceType.CONFERENCE:
 | 
			
		||||
        return statusBulkInfo.conferenceStatus;
 | 
			
		||||
      case PresenceType.IMESSENER:
 | 
			
		||||
      case PresenceType.IMESSENGER:
 | 
			
		||||
        return statusBulkInfo.imessengerStatus;
 | 
			
		||||
      default:
 | 
			
		||||
        return undefined;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user