import { Subject } from 'rxjs';
import { takeUntil, take } from 'rxjs/operators';

import {
  Component,
  OnInit,
  OnDestroy,
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Input,
  Output,
  EventEmitter,
  NgZone
} from '@angular/core';

import { Store, select } from '@ngrx/store';

import { SortOrder } from '@ucap/core';

import { VersionInfo2Response } from '@ucap/api-public';
import { LoginResponse } from '@ucap/protocol-authentication';
import {
  UserInfoSS,
  DeptSearchType,
  DeptUserRequest
} from '@ucap/protocol-query';

import { LogService } from '@ucap/ng-logger';
import {
  LoginSelector,
  ConfigurationSelector
} from '@ucap/ng-store-authentication';
import { QueryProtocolService } from '@ucap/ng-protocol-query';
import {
  DepartmentActions,
  DepartmentSelector,
  PresenceActions
} from '@ucap/ng-store-organization';

import { SearchData } from '../models/search-data';

const DEPT_ORDER_PROPERTY = 'order';

interface CheckedInfo {
  checked: boolean;
  userInfo: UserInfoSS;
}

@Component({
  selector: 'app-organization-profile-list',
  templateUrl: './profile-list.component.html',
  styleUrls: ['./profile-list.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ProfileListComponent implements OnInit, OnDestroy {
  @Input()
  set searchData(data: SearchData) {
    if (!this.loginRes) {
      this._searchData = data;
      return;
    }
    this.searchMember(data);
  }
  // tslint:disable-next-line: variable-name
  private _searchData: SearchData;

  @Input()
  selectedUser: UserInfoSS[];

  @Input()
  /** Cycle order of sorting by use ascending: undefined -> true -> false */
  set sortOrder(value: SortOrder) {
    this._sortOrder = value;
    this.userInfos = this.sort(this.userInfos);
  }
  get sortOrder() {
    return this._sortOrder;
  }
  // tslint:disable-next-line: variable-name
  _sortOrder: SortOrder = {
    property: 'name',
    ascending: undefined
  };

  @Output()
  searched: EventEmitter<UserInfoSS[]> = new EventEmitter();

  @Output()
  changedCheck: EventEmitter<CheckedInfo[]> = new EventEmitter();

  set userInfos(userInfos: UserInfoSS[]) {
    this._userInfos = userInfos;
    this.searched.emit(userInfos);
  }
  get userInfos() {
    return this._userInfos;
  }
  // tslint:disable-next-line: variable-name
  _userInfos: UserInfoSS[] = [];

  loginRes: LoginResponse;
  versionInfo2Res: VersionInfo2Response;

  processing = false;

  private ngOnDestroySubject: Subject<void> = new Subject();
  private myDeptDestroySubject: Subject<void>;

  constructor(
    private queryProtocolService: QueryProtocolService,
    private store: Store<any>,
    private changeDetectorRef: ChangeDetectorRef,
    private logService: LogService
  ) {}

  ngOnInit(): void {
    this.store
      .pipe(
        takeUntil(this.ngOnDestroySubject),
        select(ConfigurationSelector.versionInfo2Response)
      )
      .subscribe((versionInfo2Res) => {
        this.versionInfo2Res = versionInfo2Res;
      });

    this.store
      .pipe(takeUntil(this.ngOnDestroySubject), select(LoginSelector.loginRes))
      .subscribe((loginRes) => {
        this.loginRes = loginRes;
        if (!!this._searchData) {
          this.searchMember(this._searchData);
          this._searchData = undefined;
        }
      });
  }

  ngOnDestroy(): void {
    if (!!this.ngOnDestroySubject) {
      this.ngOnDestroySubject.next();
      this.ngOnDestroySubject.complete();
    }
  }

  checkAll() {
    if (!this.userInfos || 0 === this.userInfos.length) {
      return;
    }

    const checked: CheckedInfo[] = [];
    this.userInfos.forEach((u) => {
      checked.push({
        checked: true,
        userInfo: u
      });
    });
    this.changedCheck.emit(checked);
  }

  uncheckAll() {
    if (!this.userInfos || 0 === this.userInfos.length) {
      return;
    }

    const unchecked: CheckedInfo[] = [];
    this.userInfos.forEach((u) => {
      unchecked.push({
        checked: false,
        userInfo: u
      });
    });
    this.changedCheck.emit(unchecked);
  }

  /** 개별 체크여부 */
  getCheckedUser(userInfo: UserInfoSS) {
    if (!!this.selectedUser && this.selectedUser.length > 0) {
      return (
        this.selectedUser.filter((item) => item.seq === userInfo.seq).length > 0
      );
    }
    return false;
  }

  /** 개별선택(토글) 이벤트 */
  onChangeCheckUser(param: { checked: boolean; userInfo: UserInfoSS }) {
    this.changedCheck.emit([param]);
  }

  onOpenProfile(userInfo: UserInfoSS): void {
    alert('Open Profile');
  }

  private getMyDeptMember() {
    this.myDeptDestroySubject = new Subject();

    const req: DeptUserRequest = {
      divCd: 'ORG',
      companyCode: this.loginRes.companyCode,
      seq: this.loginRes.departmentCode,
      search: '',
      searchRange: DeptSearchType.All,
      senderCompanyCode: this.loginRes.companyCode,
      senderEmployeeType: this.loginRes.userInfo.employeeType
    };

    this.processing = true;

    this.store
      .pipe(
        takeUntil(this.myDeptDestroySubject),
        select(DepartmentSelector.myDepartmentUserInfoList)
      )
      .subscribe(
        (myDepartmentUserInfoList) => {
          if (!myDepartmentUserInfoList) {
            this.store.dispatch(DepartmentActions.myDeptUser({ req }));
            return;
          }
          this._refreshUserInfos(myDepartmentUserInfoList);

          this.myDeptDestroySubject.next();
          this.myDeptDestroySubject.complete();
          this.myDeptDestroySubject = undefined;
        },
        (error) => {},
        () => {
          this.processing = false;
        }
      );
  }

  private sort(userInfos: UserInfoSS[]): UserInfoSS[] {
    if (!userInfos || 0 === userInfos.length) {
      return userInfos;
    }

    const property = this.sortOrder.property;
    const ascending = this.sortOrder.ascending;
    let deptA: any;
    let deptB: any;
    let c: any;
    let d: any;

    return userInfos.slice().sort((a, b) => {
      try {
        deptA = a[DEPT_ORDER_PROPERTY];
        deptB = b[DEPT_ORDER_PROPERTY];

        if (undefined === ascending) {
          return deptA < deptB
            ? -1
            : deptA > deptB
            ? 1
            : a[property] < b[property]
            ? -1
            : a[property] > b[property]
            ? 1
            : 0;
        }

        c = ascending ? a[property] : b[property];
        d = ascending ? b[property] : a[property];

        return c < d ? -1 : c > d ? 1 : 0;
      } catch (error) {
        console.log(error);
      }
    });
  }

  private searchMember(searchData: SearchData) {
    if (
      !searchData ||
      (!searchData.bySearch && undefined === searchData.deptSeq)
    ) {
      this.getMyDeptMember();
      return;
    }

    if (!!this.myDeptDestroySubject) {
      this.myDeptDestroySubject.next();
      this.myDeptDestroySubject.complete();
      this.myDeptDestroySubject = undefined;
    }

    let req: DeptUserRequest;
    if (searchData.bySearch) {
      req = {
        divCd: 'ORGS',
        companyCode: searchData.companyCode,
        searchRange: DeptSearchType.All,
        search: searchData.searchWord,
        senderCompanyCode: this.loginRes.userInfo.companyCode,
        senderEmployeeType: this.loginRes.userInfo.employeeType
      };
    } else {
      req = {
        divCd: 'ORG',
        companyCode: this.loginRes.companyCode,
        seq: Number(searchData.deptSeq),
        search: '',
        searchRange: DeptSearchType.All,
        senderCompanyCode: this.loginRes.companyCode,
        senderEmployeeType: this.loginRes.userInfo.employeeType
      };
    }

    this.processing = true;
    this.queryProtocolService
      .deptUser(req)
      .pipe(take(1))
      .subscribe(
        (data) => {
          this._refreshUserInfos(data.userInfos);
        },
        (error) => {},
        () => {
          this.processing = false;
        }
      );
  }

  private _refreshUserInfos(userInfos: UserInfoSS[]) {
    this.userInfos = this.sort(userInfos);

    // 검색 결과에 따른 프레즌스 조회.
    const userSeqList: string[] = userInfos.map((user) => user.seq);

    if (userSeqList.length > 0) {
      this.store.dispatch(
        PresenceActions.bulkInfo({
          divCd: 'orgSrch',
          userSeqs: userSeqList
        })
      );
    }
  }
}


import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

import {
  Component,
  OnInit,
  OnDestroy,
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Input
} from '@angular/core';

import { Store, select } from '@ngrx/store';

import { VersionInfo2Response } from '@ucap/api-public';
import { UserInfoSS } from '@ucap/protocol-query';

import { LogService } from '@ucap/ng-logger';
import { PresenceSelector } from '@ucap/ng-store-organization';
import { StatusBulkInfo } from '@ucap/protocol-status';

@Component({
  selector: 'app-organization-profile-image-01',
  templateUrl: './profile-image-01.component.html',
  styleUrls: ['./profile-image-01.component.scss']
})
export class ProfileImage01Component implements OnInit, OnDestroy {
  @Input()
  set userInfo(userInfo: UserInfoSS) {
    this._userInfo = userInfo;
  }
  get userInfo(): UserInfoSS {
    return this._userInfo;
  }
  _userInfo: UserInfoSS;

  @Input()
  versionInfo: VersionInfo2Response;

  presenceInfo: StatusBulkInfo;

  private ngOnDestroySubject: Subject<void> = new Subject();

  constructor(
    private store: Store<any>,
    private changeDetectorRef: ChangeDetectorRef,
    private logService: LogService
  ) {}

  ngOnInit(): void {
    this.store
      .pipe(
        takeUntil(this.ngOnDestroySubject),
        select(
          PresenceSelector.selectStatusBulkInfo,
          Number(this.userInfo?.seq)
        )
      )
      .subscribe((status) => {
        this.presenceInfo = status;
      });
  }

  ngOnDestroy(): void {
    if (!!this.ngOnDestroySubject) {
      this.ngOnDestroySubject.next();
      this.ngOnDestroySubject.complete();
    }
  }
}


label,
contextmenu,
  profile,
  group
confirm,
error,

{
  "label": {
    "organization": "조직도",
    "selectedUsers": "선택한 대화상대",
    "addGroup": "그룹추가",
    "chat": "대화",
    "message": "쪽지",
    "call": "전화",
    "videoConference": "화상",
    "searchResult": "검색결과",
    "sortName": "이름"
  },
  "presence": {
    "offline": "오프라인",
    "online": "온라인",
    "away": "부재중",
    "statusMessage1": "다른용무중",
    "statusMessage2": "회의중",
    "statusMessage3": "집중근무중"
  }
}


{
  "label": {
    "confirmRemoveBuddy": "선택한 멤버를 삭제하시겠습니까?\n해당 그룹에서만 선택하신 멤버가 삭제됩니다."
  },
  "category": {
    "favorite": "즐겨찾기",
    "default": "기본",
    "myDept": "소속부서"
  },
  "moreMenu": {
    "show": {
      "all": "전체 보기",
      "onlineBuddy": "접속한 동료만 보기",
      "onOff": "온/오프라인 보기"
    },
    "group": {
      "addNew": "새 그룹 추가",
      "expandMore": "그룹 전체 열기",
      "expandLess": "그룹 전체 닫기",
      "changeOrder": "그룹 순서 바꾸기",
      "startChatWithGroup": "그룹 대화하기",
      "sendMessageToGroup": "그룹 쪽지 보내기",
      "groupMemberManagement": "그룹 멤버 관리",
      "changeGroupName": "그룹 이름 바꾸기",
      "removeGroup": "그룹 삭제"
    },
    "profile": {
      "open": "프로필 보기",
      "unfavorite": "즐겨찾기 해제",
      "favorite": "즐겨찾기 등록",
      "nickname": "닉네임 설정",
      "moveBuddy": "대화상대 이동",
      "copyBuddy": "대화상대 복사",
      "removeBuddy": "이 그룹에서 삭제"
    },
    "confirm": {
      "removeGroup": "그룹을 삭제하시겠습니까?<br/>그룹 멤버는 해당 그룹에서만 삭제됩니다."
    },
    "error": {
      "label": "그룹 에러",
      "requireName": "그룹명은 필수입력입니다.",
      "invalidName": "유효하지 않은 그룹명입니다.",
      "invalidSelectedUser": "선택된 유저가 존재하지 않습니다."
    }
  },

  "profile": {
    "labels": {
      "myProfile": "내 프로필",
      "company": "회사",
      "email": "이메일",
      "linePhoneNumber": "사무실",
      "mobilePhoneNumber": "핸드폰",
      "department": "부서",
      "mytalk": "MyTalk",
      "setting": "환경설정",
      "chat": "대화",
      "sms": "SMS",
      "videoConference": "화상회의",
      "message": "쪽지",
      "nickname": "닉네임 미설정"
    },
    "fields": {
      "intro": "인트로"
    },
    "errors": {}
  }
}