This commit is contained in:
Richard Park 2020-01-08 13:07:51 +09:00
commit f08964d783
34 changed files with 554 additions and 188 deletions

View File

@ -1,15 +1,16 @@
<div fxFlex fxLayout="column" fxLayoutAlign="center center">
<div class="empty-logo" fxLayoutAlign="center center" fxLayout="column">
<div
class="big-circle app-logo"
fxLayout="column"
class="big-circle app-logo border-accent-color"
fxLayoutAlign="center center"
[@animate]="{ value: '*', params: { delay: '50ms', scale: '0.2' } }"
>
<mat-icon class="s-64 s-md-128 mat-accent">chat</mat-icon>
<!--<mat-icon class="s-64 s-md-128 mat-accent">chat</mat-icon>-->
<img src="assets/images/logo/bg_logo_w120.png" />
</div>
<span
class="app-title mt-48 mb-8"
class="app-title text-accent-darkest "
[@animate]="{ value: '*', params: { delay: '100ms', y: '25px' } }"
>
{{ getTitle() }}
@ -18,9 +19,10 @@
<span
fxHide
fxShow.gt-md
class="app-message"
class="app-message secondary-text"
[@animate]="{ value: '*', params: { delay: '200ms', y: '50px' } }"
>
Select a contact to start a chat!
</span>
</div>
</div>

View File

@ -3,21 +3,29 @@
height: 100%;
flex: 1;
.empty-logo {
flex-flow: column;
transform: translateY(-100px);
.big-circle {
border-radius: 50%;
width: 240px;
height: 240px;
line-height: 240px;
text-align: center;
border: 1px solid;
width: 200px;
height: 200px;
display: flex;
justify-content: center;
justify-items: center;
}
.app-title {
margin-top: 1.4em;
font-weight: 600;
font-size: 32px;
font-size: 2.6em;
}
.secondary-text {
font-size: 16px;
margin-top: 1.4em;
font-size: 1.2em;
font-weight: 500;
color: #666666;
}
}
}

View File

@ -128,7 +128,6 @@ export class ChatComponent implements OnInit, OnDestroy, AfterViewChecked {
.pipe(
tap(([room, roomUser, roomUserShort]) => {
this.roomList = room;
this.searchRoomList = room;
this.roomUserList = roomUser;
this.roomUserShortList = roomUserShort;
@ -159,6 +158,15 @@ export class ChatComponent implements OnInit, OnDestroy, AfterViewChecked {
this.recommendedWordList = [...recommendedWordList];
if (!!this.isSearch) {
this.searchRoomList = room.filter(
roomInfo =>
this.searchRoomList.filter(
sInfo => sInfo.roomSeq === roomInfo.roomSeq
).length > 0
);
}
if (!!this.psDirectiveRef) {
this.psDirectiveRef.update();
}

View File

@ -105,6 +105,8 @@ export class GroupComponent implements OnInit, OnDestroy {
groupBuddyListSubscription: Subscription;
favoritBuddyList$: Observable<UserInfo[]>;
favoritBuddyList: UserInfo[] = [];
companyList$: Observable<Company[]>;
companyCode: string;
@ -229,9 +231,10 @@ export class GroupComponent implements OnInit, OnDestroy {
.pipe(select(AppStore.MessengerSelector.SyncSelector.selectAllBuddy2))
.pipe(
map(buddyInfoList => {
return buddyInfoList
this.favoritBuddyList = buddyInfoList
.filter(buddy => buddy.isFavorit)
.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
return this.favoritBuddyList;
})
);
}
@ -371,7 +374,11 @@ export class GroupComponent implements OnInit, OnDestroy {
menuType === 'EDIT_MEMBER' ||
menuType === 'DELETE'
) {
if (!group || group === undefined) {
if (
!group ||
group === undefined ||
(group.seq < 0 && group.name === 'Favorit')
) {
return false;
}
@ -395,7 +402,11 @@ export class GroupComponent implements OnInit, OnDestroy {
}
// 그룹원 0명인 그룹 메뉴 정리
if (menuType === 'CHAT') {
if (
menuType === 'CHAT' ||
menuType === 'SEND_MESSAGE' ||
menuType === 'DIV1'
) {
if (!!group && !!group.userSeqs && group.userSeqs.length > 0) {
return true;
} else {
@ -652,11 +663,22 @@ export class GroupComponent implements OnInit, OnDestroy {
break;
case 'SEND_MESSAGE':
{
let receiverList: UserInfo[] = [];
const isFavGroup =
group.seq < 0 && group.name === 'Favorit' ? true : false;
if (!!isFavGroup) {
receiverList = this.favoritBuddyList;
} else {
const curGroupBuddyList = this.groupBuddyList.filter(
groupInfo => groupInfo.group.seq === group.seq
);
if (!!curGroupBuddyList && curGroupBuddyList.length > 0) {
receiverList = curGroupBuddyList[0].buddyList;
}
}
if (receiverList.length > 0) {
this.dialogService.open<
MessageWriteDialogComponent,
MessageWriteDialogData,
@ -669,7 +691,7 @@ export class GroupComponent implements OnInit, OnDestroy {
data: {
loginRes: this.loginRes,
environmentsInfo: this.environmentsInfo,
receiverList: curGroupBuddyList[0].buddyList
receiverList
}
});
}

View File

@ -185,16 +185,14 @@
</mat-menu>
</div>
</div>
</mat-toolbar>
<!-- / CHAT TOOLBAR -->
<div style="position: relative;">
<div class="chat-search-frame">
<div
*ngIf="(eventListProcessing$ | async) || isTranslationProcess"
style="position: absolute; width: 100%;"
>
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
</div>
<div *ngIf="isShowSearchArea" class="char-search">
<div *ngIf="isShowSearchArea" class="chat-search bg-accent-color">
<ucap-chat-search
[totalCount]="searchTotalCount"
[curIndex]="searchCurrentIndex"
@ -206,6 +204,9 @@
></ucap-chat-search>
</div>
</div>
</mat-toolbar>
<!-- / CHAT TOOLBAR -->
<!-- CHAT CONTENT -->
<div
fxFlex="1 1 auto"
@ -239,6 +240,7 @@
[minShowReadHere]="
environment.productConfig.CommonSetting.readHereShowMinimumEventCount
"
[initRoomLastEventSeq]="initRoomLastEventSeq"
[translationSimpleview]="translationSimpleview"
(moreEvent)="onMoreEvent($event)"
(massDetail)="onMassDetail($event)"

View File

@ -23,20 +23,27 @@
width: 100%;
}
.chat-toolbar {
position: relative;
display: flex;
flex-flow: column;
width: 100%;
height: 70px;
min-height: 70px;
height: auto;
align-items: center;
background-color: #ffffff !important;
border-bottom: 1px solid #dddddd;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16);
z-index: 1;
padding: 0;
.chat-header {
width: 100%;
align-items: center;
display: flex;
justify-content: space-between;
justify-items: center;
padding: 10px 20px;
.profile-img {
margin-right: 16px;
.responsive-chats-button {
display: none;
&:last-child {
@ -87,6 +94,13 @@
margin-left: auto;
}
}
.chat-search-frame {
position: relative;
width: 100%;
.chat-search {
margin: 0 4px 4px;
}
}
}
.chat-content {
@ -152,12 +166,3 @@
}
}
}
.char-search {
width: 100%;
height: 80px;
background-color: #ffffff;
padding: 20px;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16);
border-bottom: 1px solid #dddddd;
}

View File

@ -60,10 +60,7 @@ import {
} from '@app/types';
import { RoomInfo, UserInfo, RoomType } from '@ucap-webmessenger/protocol-room';
import { tap, take, map, catchError, finalize } from 'rxjs/operators';
import {
FileInfo,
FormComponent as UCapUiChatFormComponent
} from '@ucap-webmessenger/ui-chat';
import { FormComponent as UCapUiChatFormComponent } from '@ucap-webmessenger/ui-chat';
import { KEY_VER_INFO } from '@app/types';
import { VersionInfo2Response } from '@ucap-webmessenger/api-public';
import {
@ -149,6 +146,8 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
userInfoList: UserInfo[];
userInfoListSubscription: Subscription;
eventListProcessing$: Observable<boolean>;
searchEventListProcessing: boolean;
searchEventListProcessingSubscription: Subscription;
eventInfoStatus: InfoResponse;
eventInfoStatusSubscription: Subscription;
sessionVerInfo: VersionInfo2Response;
@ -167,7 +166,7 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
interval: any;
/** About Searching */
isShowSearchArea = true;
isShowSearchArea = false;
moreSearchProcessing = false;
searchText = '';
searchedList: Info<EventJson>[];
@ -193,6 +192,7 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
/** About ReadHere */
firstcheckReadHere = true;
clearReadHere = false;
initRoomLastEventSeq: number;
snackBarPreviewEvent: MatSnackBarRef<SimpleSnackBar>;
@ -260,6 +260,25 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
select(AppStore.MessengerSelector.EventSelector.infoListProcessing)
);
this.searchEventListProcessingSubscription = this.store
.pipe(
select(
AppStore.MessengerSelector.EventSelector.infoSearchListProcessing
),
tap(process => {
this.searchEventListProcessing = process;
if (!process && this.isShowSearchArea) {
this.doSearchTextInEvent(this.searchText);
this.snackBarService.open('대화검색을 마쳤습니다.', '확인', {
duration: 3000,
verticalPosition: 'top',
horizontalPosition: 'center'
});
}
})
)
.subscribe();
this.eventRemain$ = this.store.pipe(
select(AppStore.MessengerSelector.EventSelector.remainInfo),
tap(remainInfo => {
@ -300,9 +319,9 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
if (this.moreSearchProcessing) {
const baseseq = this.baseEventSeq;
setTimeout(() => {
this.onSearchChat(this.searchText, baseseq);
}, 800);
// setTimeout(() => {
// this.doSearchTextInEvent(this.searchText, baseseq);
// }, 800);
this.baseEventSeq = infoList[0].seq;
} else {
if (!!infoList && infoList.length > 0) {
@ -340,7 +359,16 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
this.eventInfoStatusSubscription = this.store
.pipe(
select(AppStore.MessengerSelector.EventSelector.infoStatus),
tap(res => (this.eventInfoStatus = res))
tap(res => {
this.eventInfoStatus = res;
if (!!res) {
const elist = this.eventList;
if (res.baseSeq === 0 && elist.length > 0) {
this.initRoomLastEventSeq = elist[elist.length - 1].seq;
}
}
})
)
.subscribe();
@ -367,6 +395,9 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
if (!!this.eventInfoStatusSubscription) {
this.eventInfoStatusSubscription.unsubscribe();
}
if (!!this.searchEventListProcessingSubscription) {
this.searchEventListProcessingSubscription.unsubscribe();
}
clearInterval(this.interval);
}
@ -1511,6 +1542,19 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
onSearchChat(searchText: string, baseSeq?: number) {
this.searchText = searchText;
// CASE :: searching text after retrieve All event Infos.
this.store.dispatch(
EventStore.infoAll({
roomSeq: this.roomInfo.roomSeq,
baseSeq: this.eventList[0].seq,
requestCount:
environment.productConfig.CommonSetting.eventRequestDefaultCount * 2
})
);
// this.doSearchTextInEvent(searchText);
}
doSearchTextInEvent(searchText: string, baseSeq?: number): void {
this.searchedList = this.eventList.filter(event => {
let contents = '';
if (event.type === EventType.Character) {
@ -1592,6 +1636,7 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
this.moreSearchProcessing = true;
this.eventMorePosition = this.psChatContent.directiveRef.elementRef.nativeElement.scrollHeight;
// Case :: retrieve event infos step by step until include searchtext in event..
this.store.dispatch(
EventStore.infoForSearch({
req: {

View File

@ -66,10 +66,9 @@
<video
controls
*ngIf="selectedFile.info.type === FileType.Video"
[src]="getImageUrl(selectedFile)"
class="preview-video"
>
<source [src]="getImageUrl(selectedFile)" />
</video>
></video>
</div>
<ul>
<li class="name">{{ selectedFile.info.name }}</li>

View File

@ -52,7 +52,10 @@ import {
ConfirmDialogComponent,
ConfirmDialogResult,
ConfirmDialogData,
DialogService
DialogService,
AlertDialogComponent,
AlertDialogResult,
AlertDialogData
} from '@ucap-webmessenger/ui';
import { TranslateService } from '@ngx-translate/core';
@ -621,6 +624,22 @@ export class CreateChatDialogComponent implements OnInit, OnDestroy {
return;
}
if (this.inputForm.get('groupName').value.trim().length === 0) {
this.dialogService.open<
AlertDialogComponent,
AlertDialogData,
AlertDialogResult
>(AlertDialogComponent, {
data: {
title: this.translateService.instant('group.errors.label'),
html: this.translateService.instant('group.errors.requireName')
}
});
this.inputForm.setValue({ groupName: '' });
return;
}
let cfmMsg: string;
if (this.selectedUserList.length === 0) {
cfmMsg = this.translateService.instant('group.confirmAddNewWithout');
@ -653,7 +672,7 @@ export class CreateChatDialogComponent implements OnInit, OnDestroy {
selectedRoom: this.selectedRoom,
groupName:
this.data.type === UserSelectDialogType.NewGroup
? this.inputForm.get('groupName').value
? this.inputForm.get('groupName').value.trim()
: '',
oldGroup:
this.data.type === UserSelectDialogType.EditMember

View File

@ -51,7 +51,12 @@
>
{{ 'common.messages.no' | translate }}
</button>
<button mat-flat-button (click)="onClickChoice(true)" class="mat-primary">
<button
mat-flat-button
[disabled]="inputForm.invalid"
(click)="onClickChoice(true)"
class="mat-primary"
>
{{ 'common.messages.yes' | translate }}
</button>
</mat-card-actions>

View File

@ -1,10 +1,10 @@
import { RoomInfo } from '@ucap-webmessenger/protocol-room';
import { Component, OnInit, Inject, OnDestroy } from '@angular/core';
import { FormGroup, FormBuilder } from '@angular/forms';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
import { TranslateService } from '@ngx-translate/core';
import { Subscription } from 'rxjs';
import { take } from 'rxjs/operators';
import { Subscription } from 'rxjs';
export interface EditChatRoomDialogData {
title: string;
@ -30,6 +30,8 @@ export class EditChatRoomDialogComponent implements OnInit, OnDestroy {
timerArray: { value: number; text: string }[];
unitsI18nSubscription: Subscription;
constructor(
public dialogRef: MatDialogRef<
EditChatRoomDialogData,
@ -42,12 +44,15 @@ export class EditChatRoomDialogComponent implements OnInit, OnDestroy {
ngOnInit(): void {
this.inputForm = this.formBuilder.group({
roomName: [this.data.roomInfo.roomName],
roomName: [
this.data.roomInfo.roomName,
!this.data.roomInfo.isTimeRoom ? [Validators.required] : []
],
changeTarget: ['me'],
timerInterval: [this.data.roomInfo.timeRoomInterval]
});
this.translateService
this.unitsI18nSubscription = this.translateService
.get([
'common.units.hourFrom',
'common.units.minute',
@ -71,7 +76,11 @@ export class EditChatRoomDialogComponent implements OnInit, OnDestroy {
});
}
ngOnDestroy(): void {}
ngOnDestroy(): void {
if (!!this.unitsI18nSubscription) {
this.unitsI18nSubscription.unsubscribe();
}
}
onClickChoice(choice: boolean): void {
this.dialogRef.close({

View File

@ -113,7 +113,9 @@ export class TopBarComponent implements OnInit, OnDestroy {
>(KEY_VER_INFO);
// WebLink init..
if (!this.weblink || this.weblink.length === 0) {
this.initWebLink();
}
})
)
.subscribe();
@ -133,10 +135,9 @@ export class TopBarComponent implements OnInit, OnDestroy {
>(KEY_URL_INFO);
if (!!urlInfo && !!urlInfo.webLink) {
this.weblink = urlInfo.webLink.filter(
weblink =>
urlInfo.webLinkAllowedList.filter(type => type === weblink.key)
.length > 0
// order by webLinkAllowedList..
this.weblink = urlInfo.webLinkAllowedList.map(showWeblink =>
urlInfo.webLink.find(weblink => weblink.key === showWeblink)
);
if (urlInfo.webLinkAllowedList.indexOf(WebLinkType.Mail) > -1) {

View File

@ -37,8 +37,10 @@ export class AppNativeService {
subscribe(): void {
this.nativeService.logout().subscribe(() => {
this.ngZone.run(() => {
this.store.dispatch(AuthenticationStore.logoutConfirmation());
});
});
this.nativeService.changeStatus().subscribe(statusCode => {});
this.nativeService.showSetting().subscribe(() => {
this.ngZone.run(() => {

View File

@ -48,6 +48,11 @@ export const infoForSearchEnd = createAction(
props()
);
export const infoAll = createAction(
'[Messenger::Event] Info All',
props<InfoRequest>()
);
export const fileInfo = createAction(
'[Messenger::Event] File Info',
props<{ req: FileInfoRequest }>()

View File

@ -82,7 +82,8 @@ import {
fileInfoFailure,
roomOpenAfterForward,
infoForSearch,
infoForSearchEnd
infoForSearchEnd,
infoAll
} from './actions';
import { SessionStorageService } from '@ucap-webmessenger/web-storage';
import {
@ -390,6 +391,71 @@ export class Effects {
{ dispatch: false }
);
infoAll$ = createEffect(
() => {
let infoList: Info<EventJson>[];
return this.actions$.pipe(
ofType(infoAll),
tap(() => {
infoList = [];
}),
withLatestFrom(
this.store.pipe(
select(
(state: any) =>
state.messenger.event.infoSearchListProcessing as boolean
)
)
),
switchMap(([req, processing]) => {
return this.eventProtocolService.info(req).pipe(
map(async res => {
switch (res.SSVC_TYPE) {
case SSVC_TYPE_EVENT_INFO_DATA:
infoList.push(...(res as InfoData).infoList);
break;
case SSVC_TYPE_EVENT_INFO_RES:
{
this.store.dispatch(
infoMoreSuccess({
infoList,
res: res as InfoResponse,
remainInfo:
infoList.length === req.requestCount ? true : false
})
);
if (infoList.length > 0) {
if (infoList.length === req.requestCount && processing) {
// 재귀
this.store.dispatch(
infoAll({
roomSeq: req.roomSeq,
baseSeq: infoList[0].seq,
requestCount: req.requestCount
})
);
} else {
if (infoList.length < req.requestCount) {
this.store.dispatch(infoForSearchEnd({}));
}
}
} else {
this.store.dispatch(infoForSearchEnd({}));
}
}
break;
}
}),
catchError(error => of(infoFailure({ error })))
);
})
);
},
{ dispatch: false }
);
fileInfo$ = createEffect(
() => {
let fileInfoList: FileInfo[];

View File

@ -15,7 +15,8 @@ import {
infoMoreSuccess,
fileInfoSuccess,
infoForSearch,
infoForSearchEnd
infoForSearchEnd,
infoAll
} from './actions';
import * as AuthenticationStore from '@app/store/account/authentication';
import * as ChatStore from '@app/store/messenger/chat';
@ -42,6 +43,13 @@ export const reducer = createReducer(
infoSearchListProcessing: false
};
}),
on(infoAll, (state, action) => {
return {
...state,
infoListProcessing: true,
infoSearchListProcessing: true
};
}),
on(infoSuccess, (state, action) => {
return {

View File

@ -55,7 +55,11 @@
"confirmAddNew": "Do you want to add a new group?",
"confirmAddNewWith": "Do you want to add a new ({{nameOfGroup}}) group?",
"confirmAddNewWithout": "Do you want to add a new group?<br/>Created as an empty group.",
"confirmRemoveBuddyFromGroup": "Do you want to remove [{{target}}] from group?<br/>Deleting it from your profile will remove it from all groups."
"confirmRemoveBuddyFromGroup": "Do you want to remove [{{target}}] from group?<br/>Deleting it from your profile will remove it from all groups.",
"errors": {
"label": "Group errors",
"requireName": "Group name is required."
}
},
"chat": {
"label": "Chat",

View File

@ -55,7 +55,11 @@
"confirmAddNew": "새로운 그룹을 추가하시겠습니까?",
"confirmAddNewWith": "새로운 그룹({{nameOfGroup}})을 추가하시겠습니까?",
"confirmAddNewWithout": "새로운 그룹을 추가하시겠습니까?<br/>빈 그룹으로 생성됩니다.",
"confirmRemoveBuddyFromGroup": "[{{target}}]를 그룹에서 삭제하시겠습니까?<br/>프로필에서 삭제하면 모든 그룹에서 삭제됩니다."
"confirmRemoveBuddyFromGroup": "[{{target}}]를 그룹에서 삭제하시겠습니까?<br/>프로필에서 삭제하면 모든 그룹에서 삭제됩니다.",
"errors": {
"label": "그룹 에러",
"requireName": "그룹명은 필수입력입니다."
}
},
"chat": {
"label": "대화",

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -403,4 +403,9 @@ $daesang-grey: (
}
}
}
.chat-search-frame {
.chat-search {
background-color: mat-color($accent, 600, 0.7);
}
}
}

View File

@ -21,11 +21,12 @@
</div>
<ul class="event-info">
<li class="event-date bg-accent-brightest">
<span class="bg-accent-dark">날짜</span
<span class="text-accent-darkest">날짜</span
>{{ date | ucapDate: 'YYYY.MM.DD' }}
</li>
<li class="event-time bg-accent-brightest">
<span class="bg-accent-dark">시간</span>{{ date | ucapDate: 'a hh:mm' }}
<span class="text-accent-darkest">시간</span
>{{ date | ucapDate: 'a hh:mm' }}
</li>
<li class="event-content">
{{ message.sentMessageJson.title }}

View File

@ -3,10 +3,11 @@
text-align: left;
padding: 4px;
.event-header {
padding: 10px 10px 10px 36px;
padding: 10px;
font-size: 14px;
font-weight: 600;
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-calendar'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E");
text-align: center;
//background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-calendar'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: 10px center;
border-radius: 3px 3px 0 0;
@ -18,6 +19,7 @@
border-radius: 0 0 6px 6px;
background-color: #ffffff;
li {
color: #333333;
&.event-title {
margin-bottom: 10px;
padding-bottom: 10px;
@ -37,6 +39,7 @@
justify-content: center;
font-size: 0.96em;
margin-bottom: 2px;
color: #777777;
}
}
&.event-content {

View File

@ -24,39 +24,39 @@ export class ScheduleComponent implements OnInit {
ngOnInit() {
if (!!this.message && !!this.message.sentMessageJson) {
if (!!this.message.sentMessageJson.date) {
let str_date = this.message.sentMessageJson.date
let strDate = this.message.sentMessageJson.date
.replace(/ /g, '')
// .replace(/\n/g, '')
.replace(/\n/g, '')
.replace(/(\([월,화,수,목,금,토,일]\))/g, '');
if (str_date.indexOf('오전') > -1) {
str_date = str_date.replace('오전', ' ');
} else if (str_date.indexOf('오후') > -1) {
str_date = str_date.replace('오후', ' ');
const arr = str_date.split(' ');
let h = Number(arr[1].split(':')[0]) + 12;
str_date = arr[0] + ' ' + h + ':' + arr[1].split(':')[1];
if (strDate.indexOf('오전') > -1) {
strDate = strDate.replace('오전', ' ');
} else if (strDate.indexOf('오후') > -1) {
strDate = strDate.replace('오후', ' ');
const arr = strDate.split(' ');
const h = Number(arr[1].split(':')[0]) + 12;
strDate = arr[0] + ' ' + h + ':' + arr[1].split(':')[1];
}
this.date = moment(str_date).toDate();
this.date = moment(strDate).toDate();
if (this.date === 'Invalid Date') {
this.date = this.message.sentMessageJson.date.replace(/\n/g, '');
}
}
// if (!!this.message.sentMessageJson.endDate) {
// let str_endDate = this.message.sentMessageJson.endDate
// let strEndDate = this.message.sentMessageJson.endDate
// .replace(/ /g, '')
// .replace(/\n/g, '')
// .replace(/(\([월,화,수,목,금,토,일]\))/g, '');
// if (str_endDate.indexOf('오전') > -1) {
// str_endDate = str_endDate.replace('오전', ' ');
// } else if (str_endDate.indexOf('오후') > -1) {
// str_endDate = str_endDate.replace('오후', ' ');
// const arr = str_endDate.split(' ');
// let h = Number(arr[1].split(':')[0]) + 12;
// str_endDate = arr[0] + ' ' + h + ':' + arr[1].split(':')[1];
// if (strEndDate.indexOf('오전') > -1) {
// strEndDate = strEndDate.replace('오전', ' ');
// } else if (strEndDate.indexOf('오후') > -1) {
// strEndDate = strEndDate.replace('오후', ' ');
// const arr = strEndDate.split(' ');
// const h = Number(arr[1].split(':')[0]) + 12;
// strEndDate = arr[0] + ' ' + h + ':' + arr[1].split(':')[1];
// }
// this.endDate = moment(str_endDate).toDate();
// this.endDate = moment(strEndDate).toDate();
// if (this.endDate === 'Invalid Date') {
// this.endDate = this.message.sentMessageJson.endDate.replace(
// /\n/g,

View File

@ -30,7 +30,6 @@ export class MessagesComponent implements OnInit {
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;
@ -52,6 +51,8 @@ export class MessagesComponent implements OnInit {
@Input()
minShowReadHere = 10;
@Input()
initRoomLastEventSeq: number;
@Input()
translationSimpleview = false;
@Output()
@ -86,7 +87,6 @@ export class MessagesComponent implements OnInit {
moment = moment;
firstEventSeq = 0;
lastEventSeq = 0;
existReadHere = false;
constructor(private logger: NGXLogger, private datePipe: DatePipe) {}
@ -186,7 +186,8 @@ export class MessagesComponent implements OnInit {
if (
!!this.roomInfo &&
!!this.roomInfo.lastReadEventSeq &&
this.lastEventSeq - this.roomInfo.lastReadEventSeq > 5
this.initRoomLastEventSeq - this.roomInfo.lastReadEventSeq >
this.minShowReadHere
) {
if (
this.roomInfo.roomType === RoomType.Single ||

View File

@ -1,6 +1,7 @@
<div fxFlex fxLayout="row" class="chatroom-search">
<div fxLayout="row" fxLayoutAlign="start center" class="input search-form">
<form [formGroup]="fgSearch" class="w-100-p">
<i class="material-icons icon-search"> </i>
<mat-form-field floatLabel="never">
<input
matInput
@ -11,21 +12,32 @@
formControlName="searchInput"
(keydown.enter)="onKeyDownEnter($event, inputSearch.value)"
/>
<button
<!-- <button
mat-button
matSuffix
mat-icon-button
aria-label="Clear"
(click)="inputSearch.value = ''; onClickSearchCancel()"
>
-->
<button
mat-button
matSuffix
mat-icon-button
aria-label="Clear"
*ngIf="inputSearch.value"
(click)="inputSearch.value = ''"
>
<mat-icon>close</mat-icon>
</button>
</mat-form-field>
<span class="text-amount">{{ curIndex }} / {{ totalCount }}</span>
<span class="stroke-bar"></span>
</form>
</div>
<div class="btns">
<button
*ngIf="false"
mat-stroked-button
(click)="onClickSearchAndPrev()"
class="btn-toggle"
@ -81,6 +93,7 @@
<polyline class="st0" points="15.8,10 10,15.8 4.2,10 " />
</svg>
</button>
<!--<mat-button-toggle-group>
<mat-button-toggle></mat-button-toggle>
<mat-button-toggle >
@ -103,4 +116,26 @@
<mat-button-toggle ></mat-button-toggle>
</mat-button-toggle-group>-->
</div>
<span class="stroke-bar"></span>
<span class="text-amount">{{ curIndex }} / {{ totalCount }}</span>
<button
class="btn-close-searchbox bg-accent-dark"
(click)="inputSearch.value = ''; onClickSearchCancel()"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="feather feather-x"
>
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</button>
</div>

View File

@ -4,6 +4,7 @@
justify-items: center;
.search-form {
flex-flow: row;
padding: 0 10px 0 20px;
flex: 1 1 auto;
form {
display: flex;
@ -17,40 +18,86 @@
color: rgba(0, 0, 0, 0.54);
}
}
}
}
.text-amount {
display: inline-flex;
width: 80px;
min-width: 80px;
padding: 0 10px;
align-self: center;
font-size: 0.7em;
justify-content: center;
border-radius: 50px;
margin-right: 10px;
}
}
::ng-deep .search-form {
.mat-form-field-appearance-legacy {
.mat-form-field-wrapper {
color: #ffffff;
padding-bottom: 0.8em;
.mat-form-field-infix {
.mat-input-element {
font-size: 1em;
}
}
.mat-form-field-suffix {
button {
position: relative;
transform: translateY(4px);
.mat-button-wrapper {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
font-size: 1.2em;
}
}
}
.mat-form-field-label {
color: rgba(255, 255, 255, 0.7) !important;
}
.mat-form-field-underline {
height: 0;
.mat-form-field-ripple {
top: 6px;
height: 1px;
overflow: hidden;
display: none;
}
}
}
}
.icon-search {
height: 100%;
display: flex;
align-self: center;
color: #ffffff;
margin-right: 10px;
}
}
::ng-deep .chatroom-search {
position: relative;
.btns {
display: flex;
flex: 0 0 0%;
}
}
.mat-form-field-label,
.mat-hint {
color: rgba(0, 0, 0, 0.54);
}
::ng-deep .btns {
border: 1px solid #dddddd;
border-radius: 4px;
height: 42px;
height: 40px;
margin-top: 10px;
border-radius: 50px;
.mat-stroked-button {
border: none;
min-width: 40px;
height: 42px;
height: 40px;
padding: 0 10px;
overflow: hidden;
border-radius: 50%;
background-color: (0, 0, 0, 0.7);
&.btn-toggle {
display: flex;
border-right: 1px solid #dddddd;
//border-right: 1px solid #ffffff;
justify-items: center;
&:last-child {
border-right: none;
}
.mat-button-wrapper {
display: flex;
line-height: inherit;
@ -61,9 +108,32 @@
svg {
width: 100%;
height: 100%;
stroke: #555555;
stroke: #ffffff;
}
}
}
}
}
.btn-close-searchbox {
width: 3em;
height: 100%;
//background: #0367a6;
stroke: #ffffff;
border: none;
display: flex;
justify-content: center;
justify-items: center;
svg {
stroke: #ffffff;
}
}
}
.stroke-bar {
width: 2px;
height: 20px;
background-color: rgba(255, 255, 255, 0.3);
margin: 0 10px;
display: inline-flex;
align-self: center;
}

View File

@ -85,6 +85,12 @@ export class ExpansionPanelComponent
} else {
const groupNode: GroupNode = {
nodeType: NodeType.Favorit,
groupDetail: {
seq: -9999,
name: NodeType.Favorit,
isActive: true,
userSeqs: userInfoList.map(userInfo => userInfo.seq)
} as GroupDetailData,
children: []
};

View File

@ -1,4 +1,4 @@
.organization-tree {
::ng-deep .organization-tree {
padding: 5px;
.tree-node-closer-container {
@ -10,7 +10,7 @@
width: 15px;
height: 40px;
position: absolute;
border: 1px dotted grey;
border: 1px dotted #cccccc;
border-width: 0 0 1px 1px;
top: -40px;
// left: 20px;
@ -19,7 +19,7 @@
width: 15px;
height: 40px;
position: absolute;
border: 1px dotted grey;
border: 1px dotted #cccccc;
border-width: 0 0 1px 1px;
top: 0px;
// left: 20px;
@ -74,10 +74,17 @@
background-color: #eef9fd;
border: 1px solid #cee1e8;
border-radius: 4px;
padding-bottom: 10px;
//padding-bottom: 10px;
button {
line-height: normal;
.mat-button-wrapper {
width: 24px;
height: 24px;
.tree-node-expand-btn {
background-color: transparent;
font-size: 20px;
}
}
}
}
}

View File

@ -72,3 +72,6 @@ input {
a {
cursor: pointer;
}
[class*='btn'] {
cursor: pointer;
}

View File

@ -6,7 +6,7 @@
align-items: center;
text-indent: -10000000px;
margin-right: 4px;
border-radius: 100px;
border-radius: 50%;
}
.presence {
@extend %presence;

View File

@ -1,4 +1,4 @@
.fab-container {
::ng-deep .btn-main-float {
position: absolute;
bottom: 15px;
right: 40px;
@ -12,9 +12,11 @@
flex-direction: column-reverse;
align-items: center;
margin-bottom: 5px;
}
button {
margin-bottom: 17px;
.mat-button-wrapper {
line-height: normal;
}
}
}

View File

@ -1,5 +1,5 @@
<mat-card class="confirm-card mat-elevation-z">
<mat-card-header>
<mat-card-header *ngIf="data.title">
<mat-card-title>{{ data.title }}</mat-card-title>
<!-- <mat-card-subtitle>Confirm</mat-card-subtitle> -->
</mat-card-header>

View File

@ -4,7 +4,9 @@ import {
FileEventJson,
MassTextEventJson,
TranslationEventJson,
MassTranslationEventJson
MassTranslationEventJson,
PlanEventJson,
PlanContentType
} from '@ucap-webmessenger/protocol-event';
import { FileType } from '@ucap-webmessenger/protocol-file';
@ -206,6 +208,23 @@ export class StringUtil {
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;
default:
{