여기까지 읽음 기능 추가.
This commit is contained in:
parent
7501275465
commit
7a448f3f1a
|
@ -179,7 +179,6 @@
|
||||||
<div
|
<div
|
||||||
fxFlex="1 1 auto"
|
fxFlex="1 1 auto"
|
||||||
class="chat-content"
|
class="chat-content"
|
||||||
#messageBoxContainer
|
|
||||||
ucapFileUploadFor
|
ucapFileUploadFor
|
||||||
[fileUploadQueue]="fileUploadQueue"
|
[fileUploadQueue]="fileUploadQueue"
|
||||||
(fileSelected)="onFileSelected($event)"
|
(fileSelected)="onFileSelected($event)"
|
||||||
|
@ -187,6 +186,7 @@
|
||||||
(fileDragOver)="onFileDragOver()"
|
(fileDragOver)="onFileDragOver()"
|
||||||
(fileDragLeave)="onFileDragLeave()"
|
(fileDragLeave)="onFileDragLeave()"
|
||||||
>
|
>
|
||||||
|
|
||||||
<!-- CHAT MESSAGES -->
|
<!-- CHAT MESSAGES -->
|
||||||
<perfect-scrollbar
|
<perfect-scrollbar
|
||||||
fxFlex="1 1 auto"
|
fxFlex="1 1 auto"
|
||||||
|
@ -196,13 +196,16 @@
|
||||||
(psYReachEnd)="onScrollReachEnd($event)"
|
(psYReachEnd)="onScrollReachEnd($event)"
|
||||||
>
|
>
|
||||||
<ucap-chat-messages
|
<ucap-chat-messages
|
||||||
[messages]="eventList"
|
[eventList]="eventList"
|
||||||
|
[roomInfo]="roomInfo"
|
||||||
[eventInfoStatus]="eventInfoStatus"
|
[eventInfoStatus]="eventInfoStatus"
|
||||||
[eventRemain]="eventRemain$ | async"
|
[eventRemain]="eventRemain$ | async"
|
||||||
[userInfos]="userInfoList"
|
[userInfos]="userInfoList"
|
||||||
[loginRes]="loginRes"
|
[loginRes]="loginRes"
|
||||||
[sessionVerInfo]="sessionVerInfo"
|
[sessionVerInfo]="sessionVerInfo"
|
||||||
[isShowUnreadCount]="getShowUnreadCount()"
|
[isShowUnreadCount]="getShowUnreadCount()"
|
||||||
|
[clearReadHere]="clearReadHere"
|
||||||
|
[minShowReadHere]="CONST.READ_HERE_MIN_EVENT_INFO_READ_COUNT"
|
||||||
(moreEvent)="onMoreEvent($event)"
|
(moreEvent)="onMoreEvent($event)"
|
||||||
(massDetail)="onMassDetail($event)"
|
(massDetail)="onMassDetail($event)"
|
||||||
(save)="onSave($event)"
|
(save)="onSave($event)"
|
||||||
|
|
|
@ -3,7 +3,6 @@ import {
|
||||||
OnInit,
|
OnInit,
|
||||||
OnDestroy,
|
OnDestroy,
|
||||||
ViewChild,
|
ViewChild,
|
||||||
ElementRef,
|
|
||||||
AfterViewInit,
|
AfterViewInit,
|
||||||
Output,
|
Output,
|
||||||
EventEmitter
|
EventEmitter
|
||||||
|
@ -24,7 +23,7 @@ import {
|
||||||
} from '@ucap-webmessenger/ui';
|
} from '@ucap-webmessenger/ui';
|
||||||
import { Store, select } from '@ngrx/store';
|
import { Store, select } from '@ngrx/store';
|
||||||
import { NGXLogger } from 'ngx-logger';
|
import { NGXLogger } from 'ngx-logger';
|
||||||
import { Observable, Subscription, forkJoin, of } from 'rxjs';
|
import { Observable, Subscription, forkJoin, of, combineLatest } from 'rxjs';
|
||||||
import {
|
import {
|
||||||
Info,
|
Info,
|
||||||
EventType,
|
EventType,
|
||||||
|
@ -109,9 +108,6 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
@Output()
|
@Output()
|
||||||
openProfile = new EventEmitter<UserInfo>();
|
openProfile = new EventEmitter<UserInfo>();
|
||||||
|
|
||||||
@ViewChild('messageBoxContainer', { static: true })
|
|
||||||
private messageBoxContainer: ElementRef;
|
|
||||||
|
|
||||||
@ViewChild('chatForm', { static: false })
|
@ViewChild('chatForm', { static: false })
|
||||||
private chatForm: UCapUiChatFormComponent;
|
private chatForm: UCapUiChatFormComponent;
|
||||||
|
|
||||||
|
@ -159,9 +155,14 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
isShowStickerSelector = false;
|
isShowStickerSelector = false;
|
||||||
selectedSticker: StickerFilesInfo;
|
selectedSticker: StickerFilesInfo;
|
||||||
|
|
||||||
|
/** About ReadHere */
|
||||||
|
firstcheckReadHere = true;
|
||||||
|
clearReadHere = false;
|
||||||
|
|
||||||
snackBarPreviewEvent: MatSnackBarRef<SimpleSnackBar>;
|
snackBarPreviewEvent: MatSnackBarRef<SimpleSnackBar>;
|
||||||
|
|
||||||
RoomType = RoomType;
|
RoomType = RoomType;
|
||||||
|
CONST = CONST;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private store: Store<any>,
|
private store: Store<any>,
|
||||||
|
@ -229,10 +230,15 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
this.eventListSubscription = this.store
|
// [Daesang]
|
||||||
|
this.eventListSubscription = combineLatest([
|
||||||
|
this.store.pipe(
|
||||||
|
select(AppStore.MessengerSelector.EventSelector.selectAllInfoList)
|
||||||
|
),
|
||||||
|
this.store.pipe(select(AppStore.MessengerSelector.RoomSelector.roomInfo))
|
||||||
|
])
|
||||||
.pipe(
|
.pipe(
|
||||||
select(AppStore.MessengerSelector.EventSelector.selectAllInfoList),
|
tap(([infoList, roomInfo]) => {
|
||||||
tap(infoList => {
|
|
||||||
if (!!this.eventList && this.eventList.length > 0) {
|
if (!!this.eventList && this.eventList.length > 0) {
|
||||||
this.eventListNew = infoList.filter(info => {
|
this.eventListNew = infoList.filter(info => {
|
||||||
if (info.seq <= this.eventList[this.eventList.length - 1].seq) {
|
if (info.seq <= this.eventList[this.eventList.length - 1].seq) {
|
||||||
|
@ -240,7 +246,20 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (
|
||||||
|
!!infoList &&
|
||||||
|
infoList.length > 0 &&
|
||||||
|
!!roomInfo &&
|
||||||
|
!!roomInfo.lastReadEventSeq &&
|
||||||
|
roomInfo.lastReadEventSeq > 0 &&
|
||||||
|
this.baseEventSeq <= roomInfo.lastReadEventSeq
|
||||||
|
) {
|
||||||
|
// 조회된 내용중에 read here 가 있을 경우.
|
||||||
|
this.firstcheckReadHere = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.eventList = infoList;
|
this.eventList = infoList;
|
||||||
|
|
||||||
if (!!infoList && infoList.length > 0) {
|
if (!!infoList && infoList.length > 0) {
|
||||||
|
@ -251,6 +270,29 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
)
|
)
|
||||||
.subscribe();
|
.subscribe();
|
||||||
|
|
||||||
|
// // [GROUP]
|
||||||
|
// this.eventListSubscription = this.store
|
||||||
|
// .pipe(
|
||||||
|
// select(AppStore.MessengerSelector.EventSelector.selectAllInfoList),
|
||||||
|
// tap(infoList => {
|
||||||
|
// if (!!this.eventList && this.eventList.length > 0) {
|
||||||
|
// this.eventListNew = infoList.filter(info => {
|
||||||
|
// if (info.seq <= this.eventList[this.eventList.length - 1].seq) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// return true;
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// this.eventList = infoList;
|
||||||
|
|
||||||
|
// if (!!infoList && infoList.length > 0) {
|
||||||
|
// this.baseEventSeq = infoList[0].seq;
|
||||||
|
// this.readyToReply();
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// )
|
||||||
|
// .subscribe();
|
||||||
|
|
||||||
this.eventInfoStatusSubscription = this.store
|
this.eventInfoStatusSubscription = this.store
|
||||||
.pipe(
|
.pipe(
|
||||||
select(AppStore.MessengerSelector.EventSelector.infoStatus),
|
select(AppStore.MessengerSelector.EventSelector.infoStatus),
|
||||||
|
@ -296,6 +338,8 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
// Sticker Selector Clear..
|
// Sticker Selector Clear..
|
||||||
this.isShowStickerSelector = false;
|
this.isShowStickerSelector = false;
|
||||||
this.selectedSticker = undefined;
|
this.selectedSticker = undefined;
|
||||||
|
|
||||||
|
this.firstcheckReadHere = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
get _roomUserInfos() {
|
get _roomUserInfos() {
|
||||||
|
@ -395,15 +439,27 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
if (this.psChatContent.directiveRef) {
|
if (this.psChatContent.directiveRef) {
|
||||||
this.psChatContent.directiveRef.update();
|
this.psChatContent.directiveRef.update();
|
||||||
|
|
||||||
setTimeout(() => {
|
const element = document.getElementById('message-box-readhere');
|
||||||
this.psChatContent.directiveRef.scrollToTop(
|
if (!!element && this.firstcheckReadHere) {
|
||||||
this.psChatContent.directiveRef.elementRef.nativeElement
|
setTimeout(() => {
|
||||||
.scrollHeight - this.eventMorePosition,
|
this.psChatContent.directiveRef.scrollToTop(
|
||||||
speed
|
element.offsetTop - 200,
|
||||||
);
|
speed
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
this.eventMorePosition = 0;
|
this.firstcheckReadHere = false;
|
||||||
});
|
} else {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.psChatContent.directiveRef.scrollToTop(
|
||||||
|
this.psChatContent.directiveRef.elementRef.nativeElement
|
||||||
|
.scrollHeight - this.eventMorePosition,
|
||||||
|
speed
|
||||||
|
);
|
||||||
|
|
||||||
|
this.eventMorePosition = 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (this.scrollUpinit) {
|
} else if (this.scrollUpinit) {
|
||||||
if (!!this.eventListNew && this.eventListNew.length > 0) {
|
if (!!this.eventListNew && this.eventListNew.length > 0) {
|
||||||
|
@ -437,9 +493,21 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
if (this.psChatContent.directiveRef) {
|
if (this.psChatContent.directiveRef) {
|
||||||
this.psChatContent.directiveRef.update();
|
this.psChatContent.directiveRef.update();
|
||||||
|
|
||||||
setTimeout(() => {
|
const element = document.getElementById('message-box-readhere');
|
||||||
this.psChatContent.directiveRef.scrollToBottom(0, speed);
|
if (!!element && this.firstcheckReadHere) {
|
||||||
});
|
setTimeout(() => {
|
||||||
|
this.psChatContent.directiveRef.scrollToTop(
|
||||||
|
element.offsetTop - 200,
|
||||||
|
speed
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.firstcheckReadHere = false;
|
||||||
|
} else {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.psChatContent.directiveRef.scrollToBottom(0, speed);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -447,13 +515,19 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
this.scrollUpinit = true;
|
this.scrollUpinit = true;
|
||||||
}
|
}
|
||||||
onScrollReachStart(event: any) {
|
onScrollReachStart(event: any) {
|
||||||
this.onMoreEvent(this.baseEventSeq);
|
// 자동 스크롤이 아닌 버튼 방식으로 변경.
|
||||||
|
// this.onMoreEvent(this.baseEventSeq);
|
||||||
}
|
}
|
||||||
onScrollReachEnd(event: any) {
|
onScrollReachEnd(event: any) {
|
||||||
this.setEventMoreInit();
|
this.setEventMoreInit();
|
||||||
if (!!this.snackBarPreviewEvent) {
|
if (!!this.snackBarPreviewEvent) {
|
||||||
this.snackBarPreviewEvent.dismiss();
|
this.snackBarPreviewEvent.dismiss();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clear readHere object..
|
||||||
|
if (!this.firstcheckReadHere) {
|
||||||
|
this.clearReadHere = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** More Event */
|
/** More Event */
|
||||||
|
|
|
@ -32,6 +32,7 @@ export const infoSuccess = createAction(
|
||||||
props<{
|
props<{
|
||||||
infoList: Info<EventJson>[];
|
infoList: Info<EventJson>[];
|
||||||
res: InfoResponse;
|
res: InfoResponse;
|
||||||
|
remainInfo: boolean;
|
||||||
}>()
|
}>()
|
||||||
);
|
);
|
||||||
export const infoFailure = createAction(
|
export const infoFailure = createAction(
|
||||||
|
@ -61,6 +62,7 @@ export const infoMoreSuccess = createAction(
|
||||||
props<{
|
props<{
|
||||||
infoList: Info<EventJson>[];
|
infoList: Info<EventJson>[];
|
||||||
res: InfoResponse;
|
res: InfoResponse;
|
||||||
|
remainInfo: boolean;
|
||||||
}>()
|
}>()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -106,14 +106,47 @@ import { RoomUserData } from '@ucap-webmessenger/protocol-sync';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class Effects {
|
export class Effects {
|
||||||
|
// selectedRoomForInfo$ = createEffect(() =>
|
||||||
|
// this.actions$.pipe(
|
||||||
|
// ofType(ChatStore.selectedRoom),
|
||||||
|
// map(action => {
|
||||||
|
// return info({
|
||||||
|
// roomSeq: action.roomSeq,
|
||||||
|
// baseSeq: 0,
|
||||||
|
// requestCount: CONST.EVENT_INFO_READ_COUNT
|
||||||
|
// });
|
||||||
|
// })
|
||||||
|
// )
|
||||||
|
// );
|
||||||
|
|
||||||
selectedRoomForInfo$ = createEffect(() =>
|
selectedRoomForInfo$ = createEffect(() =>
|
||||||
this.actions$.pipe(
|
this.actions$.pipe(
|
||||||
ofType(ChatStore.selectedRoom),
|
ofType(RoomStore.infoSuccess),
|
||||||
map(action => {
|
map(action => {
|
||||||
|
const roomInfo = action.roomInfo;
|
||||||
|
let requestCount = 0;
|
||||||
|
|
||||||
|
// 여기까지 읽음 처리..
|
||||||
|
if (!!roomInfo.finalEventSeq && !!roomInfo.lastReadEventSeq) {
|
||||||
|
requestCount = roomInfo.finalEventSeq - roomInfo.lastReadEventSeq;
|
||||||
|
|
||||||
|
// 기존 요청개수보다 요청할 갯수가 적을 경우 기본값.
|
||||||
|
if (CONST.EVENT_INFO_READ_COUNT >= requestCount) {
|
||||||
|
requestCount = CONST.EVENT_INFO_READ_COUNT;
|
||||||
|
} else {
|
||||||
|
// 여기까지 읽음 처리를 위한 최대 요청 개수 제한.
|
||||||
|
if (CONST.READ_HERE_MAX_EVENT_INFO_READ_COUNT < requestCount) {
|
||||||
|
requestCount = CONST.READ_HERE_MAX_EVENT_INFO_READ_REQUEST_COUNT;
|
||||||
|
} else {
|
||||||
|
requestCount = requestCount + 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return info({
|
return info({
|
||||||
roomSeq: action.roomSeq,
|
roomSeq: roomInfo.roomSeq,
|
||||||
baseSeq: 0,
|
baseSeq: 0,
|
||||||
requestCount: CONST.EVENT_INFO_READ_COUNT
|
requestCount
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
@ -141,14 +174,18 @@ export class Effects {
|
||||||
this.store.dispatch(
|
this.store.dispatch(
|
||||||
infoSuccess({
|
infoSuccess({
|
||||||
infoList,
|
infoList,
|
||||||
res: res as InfoResponse
|
res: res as InfoResponse,
|
||||||
|
remainInfo:
|
||||||
|
infoList.length === req.requestCount ? true : false
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
this.store.dispatch(
|
this.store.dispatch(
|
||||||
infoMoreSuccess({
|
infoMoreSuccess({
|
||||||
infoList,
|
infoList,
|
||||||
res: res as InfoResponse
|
res: res as InfoResponse,
|
||||||
|
remainInfo:
|
||||||
|
infoList.length === req.requestCount ? true : false
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,11 +37,7 @@ export const reducer = createReducer(
|
||||||
}),
|
}),
|
||||||
infoStatus: action.res,
|
infoStatus: action.res,
|
||||||
infoListProcessing: false,
|
infoListProcessing: false,
|
||||||
remainInfo:
|
remainInfo: action.remainInfo
|
||||||
!!action.infoList &&
|
|
||||||
action.infoList.length === CONST.EVENT_INFO_READ_COUNT
|
|
||||||
? true
|
|
||||||
: false
|
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
on(infoMoreSuccess, (state, action) => {
|
on(infoMoreSuccess, (state, action) => {
|
||||||
|
@ -52,11 +48,7 @@ export const reducer = createReducer(
|
||||||
}),
|
}),
|
||||||
infoStatus: action.res,
|
infoStatus: action.res,
|
||||||
infoListProcessing: false,
|
infoListProcessing: false,
|
||||||
remainInfo:
|
remainInfo: action.remainInfo
|
||||||
!!action.infoList &&
|
|
||||||
action.infoList.length === CONST.EVENT_INFO_READ_COUNT
|
|
||||||
? true
|
|
||||||
: false
|
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
on(infoFailure, (state, action) => {
|
on(infoFailure, (state, action) => {
|
||||||
|
|
|
@ -1,10 +1,17 @@
|
||||||
export enum CONST {
|
export enum CONST {
|
||||||
/** 대용량 텍스트로 보내는 문자열의 길이 기준 */
|
/** 대용량 텍스트로 보내는 문자열의 길이 기준 */
|
||||||
MASSTEXT_LEN = 800,
|
MASSTEXT_LEN = 800,
|
||||||
/** 대화방의 이벤트를 조회하는 개수 */
|
/** 대화방의 이벤트를 조회하는 갯수 */
|
||||||
EVENT_INFO_READ_COUNT = 50,
|
EVENT_INFO_READ_COUNT = 50,
|
||||||
/** Timer Room 최초 오픈시 timer interval */
|
/** Timer Room 최초 오픈시 timer interval */
|
||||||
DEFAULT_TIMER_ROOM_INTERVAL = 24 * 60 * 60,
|
DEFAULT_TIMER_ROOM_INTERVAL = 24 * 60 * 60,
|
||||||
/** 한번에 채팅을 할 수 있는 인원수 제한 */
|
/** 한번에 채팅을 할 수 있는 인원수 제한 */
|
||||||
CHATROOM_USER = 300
|
CHATROOM_USER = 300,
|
||||||
|
|
||||||
|
/** 여기까지 읽음을 표시할때 조회할 최소 이벤트 갯수 */
|
||||||
|
READ_HERE_MIN_EVENT_INFO_READ_COUNT = 10,
|
||||||
|
/** 여기까지 읽음을 표시할때 조회할 최대 이벤트 갯수 */
|
||||||
|
READ_HERE_MAX_EVENT_INFO_READ_COUNT = 100,
|
||||||
|
/** 여기까지 읽음을 표시할때 조회할 최대 이벤트 갯수를 초과 했을 경우 요청할 최초 이벤트 갯수 */
|
||||||
|
READ_HERE_MAX_EVENT_INFO_READ_REQUEST_COUNT = 10
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,4 +28,12 @@ export interface RoomInfo {
|
||||||
isTimeRoom: boolean;
|
isTimeRoom: boolean;
|
||||||
/** 12. 타이머시간(n) */
|
/** 12. 타이머시간(n) */
|
||||||
timeRoomInterval: number;
|
timeRoomInterval: number;
|
||||||
|
|
||||||
|
// [Daesang]
|
||||||
|
/** PIN 정렬정보 */
|
||||||
|
pinOrderInfo?: string;
|
||||||
|
/** 마지막 읽은 이벤트SEQ */
|
||||||
|
lastReadEventSeq?: number;
|
||||||
|
/** 최종대화SEQ */
|
||||||
|
finalEventSeq?: number;
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,7 +94,11 @@ export const decodeInfoData: ProtocolDecoder<InfoData> = (
|
||||||
isJoinRoom: info[9] === 'Y' ? true : false,
|
isJoinRoom: info[9] === 'Y' ? true : false,
|
||||||
expiredFileStdSeq: Number(info[10]),
|
expiredFileStdSeq: Number(info[10]),
|
||||||
isTimeRoom: info[11] === 'Y' ? true : false,
|
isTimeRoom: info[11] === 'Y' ? true : false,
|
||||||
timeRoomInterval: info[11] !== 'Y' ? 0 : Number(info[12]) || 0
|
timeRoomInterval: info[11] !== 'Y' ? 0 : Number(info[12]) || 0,
|
||||||
|
|
||||||
|
pinOrderInfo: info[13],
|
||||||
|
lastReadEventSeq: Number(info[14]),
|
||||||
|
finalEventSeq: Number(info[15])
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,11 @@ export const decodeRoomData: ProtocolDecoder<RoomData> = (
|
||||||
isJoinRoom: info[9] === 'Y' ? true : false,
|
isJoinRoom: info[9] === 'Y' ? true : false,
|
||||||
expiredFileStdSeq: Number(info[10]),
|
expiredFileStdSeq: Number(info[10]),
|
||||||
isTimeRoom: info[11] === 'Y' ? true : false,
|
isTimeRoom: info[11] === 'Y' ? true : false,
|
||||||
timeRoomInterval: info[11] !== 'Y' ? 0 : Number(info[12]) || 0
|
timeRoomInterval: info[11] !== 'Y' ? 0 : Number(info[12]) || 0,
|
||||||
|
|
||||||
|
pinOrderInfo: info[13],
|
||||||
|
lastReadEventSeq: Number(info[14]),
|
||||||
|
finalEventSeq: Number(info[15])
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
<div class="read-here">
|
||||||
|
<span class="line"></span>
|
||||||
|
<span>여기까지 읽었습니다.</span>
|
||||||
|
<span class="line"></span>
|
||||||
|
</div>
|
|
@ -0,0 +1,18 @@
|
||||||
|
.read-here {
|
||||||
|
display: flex;
|
||||||
|
align-content: center;
|
||||||
|
flex-flow: row;
|
||||||
|
.line {
|
||||||
|
height: 1px;
|
||||||
|
background-color: #cccccc;
|
||||||
|
width: 40%;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.date {
|
||||||
|
width: 160px;
|
||||||
|
font-size: 13px;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ReadHereComponent } from './read-here.component';
|
||||||
|
|
||||||
|
describe('Chat::MessageBox::ReadHereComponent', () => {
|
||||||
|
let component: ReadHereComponent;
|
||||||
|
let fixture: ComponentFixture<ReadHereComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [ReadHereComponent]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(ReadHereComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ucap-chat-message-box-read-here',
|
||||||
|
templateUrl: './read-here.component.html',
|
||||||
|
styleUrls: ['./read-here.component.scss']
|
||||||
|
})
|
||||||
|
export class ReadHereComponent implements OnInit {
|
||||||
|
constructor() {}
|
||||||
|
|
||||||
|
ngOnInit() {}
|
||||||
|
}
|
|
@ -1,7 +1,20 @@
|
||||||
<div class="chat-messages" #scrollMe>
|
<div class="chat-messages" #scrollMe>
|
||||||
<!-- <div class="message-row" *ngIf="eventRemain">
|
<div class="message-row" *ngIf="eventRemain">
|
||||||
<button mat-button (click)="onClickMore($event)">이전 대화 보기</button>
|
<button mat-button (click)="onClickMore($event)">
|
||||||
</div> -->
|
이전 대화 보기
|
||||||
|
<span
|
||||||
|
*ngIf="
|
||||||
|
!!roomInfo &&
|
||||||
|
!!firstEventSeq &&
|
||||||
|
roomInfo.lastReadEventSeq < firstEventSeq
|
||||||
|
"
|
||||||
|
>
|
||||||
|
안읽은 메시지가 더 있습니다.({{
|
||||||
|
firstEventSeq - (roomInfo.lastReadEventSeq + 1)
|
||||||
|
}})개
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<!-- MESSAGE -->
|
<!-- MESSAGE -->
|
||||||
<div
|
<div
|
||||||
*ngFor="let message of messages; let i = index"
|
*ngFor="let message of messages; let i = index"
|
||||||
|
@ -11,6 +24,13 @@
|
||||||
contact: message.senderSeq !== loginRes.userSeq
|
contact: message.senderSeq !== loginRes.userSeq
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
|
<ucap-chat-message-box-read-here
|
||||||
|
id="message-box-readhere"
|
||||||
|
*ngIf="getReadHere(i) && existReadHere && !clearReadHere"
|
||||||
|
class="date-splitter"
|
||||||
|
>
|
||||||
|
</ucap-chat-message-box-read-here>
|
||||||
|
|
||||||
<ucap-chat-message-box-date-splitter
|
<ucap-chat-message-box-date-splitter
|
||||||
*ngIf="getDateSplitter(i)"
|
*ngIf="getDateSplitter(i)"
|
||||||
class="date-splitter"
|
class="date-splitter"
|
||||||
|
|
|
@ -1,13 +1,5 @@
|
||||||
import { CONST } from '@ucap-webmessenger/core';
|
import { CONST } from '@ucap-webmessenger/core';
|
||||||
import {
|
import { Component, OnInit, Input, EventEmitter, Output } from '@angular/core';
|
||||||
Component,
|
|
||||||
OnInit,
|
|
||||||
Input,
|
|
||||||
EventEmitter,
|
|
||||||
Output,
|
|
||||||
ViewEncapsulation,
|
|
||||||
HostListener
|
|
||||||
} from '@angular/core';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Info,
|
Info,
|
||||||
|
@ -17,7 +9,7 @@ import {
|
||||||
FileEventJson
|
FileEventJson
|
||||||
} from '@ucap-webmessenger/protocol-event';
|
} from '@ucap-webmessenger/protocol-event';
|
||||||
import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
|
import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
|
||||||
import { UserInfo } from '@ucap-webmessenger/protocol-room';
|
import { UserInfo, RoomInfo, RoomType } from '@ucap-webmessenger/protocol-room';
|
||||||
import { NGXLogger } from 'ngx-logger';
|
import { NGXLogger } from 'ngx-logger';
|
||||||
import { VersionInfo2Response } from '@ucap-webmessenger/api-public';
|
import { VersionInfo2Response } from '@ucap-webmessenger/api-public';
|
||||||
import { FileInfo } from '../models/file-info.json';
|
import { FileInfo } from '../models/file-info.json';
|
||||||
|
@ -33,7 +25,16 @@ export class MessagesComponent implements OnInit {
|
||||||
@Input()
|
@Input()
|
||||||
loginRes: LoginResponse;
|
loginRes: LoginResponse;
|
||||||
@Input()
|
@Input()
|
||||||
messages: Info<EventJson>[];
|
roomInfo: RoomInfo;
|
||||||
|
@Input()
|
||||||
|
set eventList(elist: Info<EventJson>[]) {
|
||||||
|
if (!!elist && elist.length > 0) {
|
||||||
|
this.firstEventSeq = elist[0].seq;
|
||||||
|
this.lastEventSeq = elist[elist.length - 1].seq;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.messages = elist;
|
||||||
|
}
|
||||||
@Input()
|
@Input()
|
||||||
eventInfoStatus?: InfoResponse;
|
eventInfoStatus?: InfoResponse;
|
||||||
@Input()
|
@Input()
|
||||||
|
@ -44,6 +45,10 @@ export class MessagesComponent implements OnInit {
|
||||||
sessionVerInfo: VersionInfo2Response;
|
sessionVerInfo: VersionInfo2Response;
|
||||||
@Input()
|
@Input()
|
||||||
isShowUnreadCount = true;
|
isShowUnreadCount = true;
|
||||||
|
@Input()
|
||||||
|
clearReadHere: boolean;
|
||||||
|
@Input()
|
||||||
|
minShowReadHere = 10;
|
||||||
|
|
||||||
@Output()
|
@Output()
|
||||||
openProfile = new EventEmitter<UserInfo>();
|
openProfile = new EventEmitter<UserInfo>();
|
||||||
|
@ -61,11 +66,17 @@ export class MessagesComponent implements OnInit {
|
||||||
message: Info<EventJson>;
|
message: Info<EventJson>;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
messages: Info<EventJson>[];
|
||||||
|
|
||||||
EventType = EventType;
|
EventType = EventType;
|
||||||
CONST = CONST;
|
CONST = CONST;
|
||||||
profileImageRoot: string;
|
profileImageRoot: string;
|
||||||
moment = moment;
|
moment = moment;
|
||||||
|
|
||||||
|
firstEventSeq = 0;
|
||||||
|
lastEventSeq = 0;
|
||||||
|
existReadHere = false;
|
||||||
|
|
||||||
constructor(private logger: NGXLogger, private datePipe: DatePipe) {}
|
constructor(private logger: NGXLogger, private datePipe: DatePipe) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
@ -165,6 +176,31 @@ export class MessagesComponent implements OnInit {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getReadHere(messageIndex: number): boolean {
|
||||||
|
if (
|
||||||
|
!!this.roomInfo &&
|
||||||
|
!!this.roomInfo.lastReadEventSeq &&
|
||||||
|
this.roomInfo.lastReadEventSeq > 0 &&
|
||||||
|
this.lastEventSeq - this.roomInfo.lastReadEventSeq > 5
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
this.roomInfo.roomType === RoomType.Single ||
|
||||||
|
this.roomInfo.roomType === RoomType.Multi
|
||||||
|
) {
|
||||||
|
if (!this.roomInfo.isTimeRoom) {
|
||||||
|
if (
|
||||||
|
this.messages[messageIndex].seq ===
|
||||||
|
this.roomInfo.lastReadEventSeq + 1
|
||||||
|
) {
|
||||||
|
this.existReadHere = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
onClickOpenProfile(event: MouseEvent, userInfo: UserInfo) {
|
onClickOpenProfile(event: MouseEvent, userInfo: UserInfo) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
|
|
@ -23,6 +23,7 @@ import { InformationComponent as MBInformationComponent } from './components/mes
|
||||||
import { MassTranslationComponent as MBMassTranslationComponent } from './components/message-box/mass-translation.component';
|
import { MassTranslationComponent as MBMassTranslationComponent } from './components/message-box/mass-translation.component';
|
||||||
import { MassComponent as MBMassComponent } from './components/message-box/mass.component';
|
import { MassComponent as MBMassComponent } from './components/message-box/mass.component';
|
||||||
import { NoticeComponent as MBNoticeComponent } from './components/message-box/notice.component';
|
import { NoticeComponent as MBNoticeComponent } from './components/message-box/notice.component';
|
||||||
|
import { ReadHereComponent as MBReadHereComponent } from './components/message-box/read-here.component';
|
||||||
import { RecallComponent as MBRecallComponent } from './components/message-box/recall.component';
|
import { RecallComponent as MBRecallComponent } from './components/message-box/recall.component';
|
||||||
import { ScheduleComponent as MBScheduleComponent } from './components/message-box/schedule.component';
|
import { ScheduleComponent as MBScheduleComponent } from './components/message-box/schedule.component';
|
||||||
import { StickerComponent as MBStickerComponent } from './components/message-box/sticker.component';
|
import { StickerComponent as MBStickerComponent } from './components/message-box/sticker.component';
|
||||||
|
@ -43,6 +44,7 @@ const COMPONENTS = [
|
||||||
MBMassTranslationComponent,
|
MBMassTranslationComponent,
|
||||||
MBMassComponent,
|
MBMassComponent,
|
||||||
MBNoticeComponent,
|
MBNoticeComponent,
|
||||||
|
MBReadHereComponent,
|
||||||
MBRecallComponent,
|
MBRecallComponent,
|
||||||
MBScheduleComponent,
|
MBScheduleComponent,
|
||||||
MBStickerComponent,
|
MBStickerComponent,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user