diff --git a/src/app/module/chat/data/data-source/message/message-remote-data-source.service.ts b/src/app/module/chat/data/data-source/message/message-remote-data-source.service.ts index 68fb2dc72..af654b5ff 100644 --- a/src/app/module/chat/data/data-source/message/message-remote-data-source.service.ts +++ b/src/app/module/chat/data/data-source/message/message-remote-data-source.service.ts @@ -3,7 +3,7 @@ import { HttpService } from 'src/app/services/http.service'; import { MessageInputDTO, MessageInputDTOSchema } from '../../dto/message/messageInputDtO'; import { ValidateSchema } from 'src/app/services/decorators/validate-schema.decorator'; import { APIReturn } from 'src/app/services/decorators/api-validate-schema.decorator'; -import { MessageOutPutDTO, MessageOutPutDTOSchema } from '../../dto/message/messageOutputDTO'; +import { MessageOutPutDataDTOSchema, MessageOutPutDTO, MessageOutPutDTOSchema } from '../../dto/message/messageOutputDTO'; import { DataSourceReturn } from 'src/app/services/Repositorys/type'; @Injectable({ @@ -15,7 +15,7 @@ export class MessageRemoteDataSourceService { constructor(private httpService: HttpService) {} - @APIReturn(MessageOutPutDTOSchema, 'get/Messages') + @APIReturn(MessageOutPutDTOSchema, 'post/Messages') @ValidateSchema(MessageInputDTOSchema) async sendMessage(data: MessageInputDTO) { return await this.httpService.post(`${this.baseUrl}/Messages`, data); @@ -25,6 +25,7 @@ export class MessageRemoteDataSourceService { return await this.httpService.post(`${this.baseUrl}/Messages/${id}/React`, reaction); } + @APIReturn(MessageOutPutDTOSchema, 'get/Messages') async getMessagesFromRoom(id: string): DataSourceReturn { return await this.httpService.get(`${this.baseUrl}/Room/${id}/Messages`); } diff --git a/src/app/module/chat/data/dto/message/messageOutputDTO.ts b/src/app/module/chat/data/dto/message/messageOutputDTO.ts index bee587658..de6f2cf20 100644 --- a/src/app/module/chat/data/dto/message/messageOutputDTO.ts +++ b/src/app/module/chat/data/dto/message/messageOutputDTO.ts @@ -12,24 +12,23 @@ export enum MessageAttachmentFileType { Video } -const DataSchema = z.object({ +export const MessageOutPutDataDTOSchema = z.object({ id: z.string(), roomId: z.string(), - wxUserId: z.number(), sender: z.object({ wxUserId: z.number(), wxFullName: z.string(), wxeMail: z.string(), userPhoto: z.string().optional() }).nullable(), - message: z.string(), + message: z.string().nullable(), messageType: z.number(), sentAt: z.string(), deliverAt: z.string().datetime().nullable(), canEdit: z.boolean(), oneShot: z.boolean(), requireUnlock: z.boolean(), - requestId: z.string(), + requestId: z.string().optional(), reactions: z.object({ id: z.string(), reactedAt: z.string(), @@ -50,8 +49,8 @@ const DataSchema = z.object({ export const MessageOutPutDTOSchema = z.object({ success: z.boolean(), message: z.string(), - data: DataSchema.array() + data: MessageOutPutDataDTOSchema.array() }); -export type MessageOutPutDataDTO = z.infer +export type MessageOutPutDataDTO = z.infer export type MessageOutPutDTO = z.infer diff --git a/src/app/module/chat/domain/use-case/message-delete-live-use-case.service.ts b/src/app/module/chat/domain/use-case/message-delete-live-use-case.service.ts index 1ba6e1b18..9838bea5a 100644 --- a/src/app/module/chat/domain/use-case/message-delete-live-use-case.service.ts +++ b/src/app/module/chat/domain/use-case/message-delete-live-use-case.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@angular/core'; import { z } from 'zod'; import { MessageRepositoryService } from '../../data/repository/message-respository.service'; -import { ValidateSchema } from 'src/app/services/decorators/validate-schema.decorator'; +import { SafeValidateSchema, ValidateSchema } from 'src/app/services/decorators/validate-schema.decorator'; export const MessageDeleteInputDTOSchema = z.object({ requestId: z.string().optional(), @@ -20,7 +20,7 @@ export class MessageDeleteLiveUseCaseService { public repository: MessageRepositoryService ) { } - @ValidateSchema(MessageDeleteInputDTOSchema) + @SafeValidateSchema(MessageDeleteInputDTOSchema, 'MessageDeleteLiveUseCaseService') async execute(data: MessageDeleteInputDTO) { return this.repository.sendMessageDelete(data) } diff --git a/src/app/module/chat/domain/use-case/socket/socket-message-update-use-case.service.ts b/src/app/module/chat/domain/use-case/socket/socket-message-update-use-case.service.ts index 7e4f1fcca..a3955ffb2 100644 --- a/src/app/module/chat/domain/use-case/socket/socket-message-update-use-case.service.ts +++ b/src/app/module/chat/domain/use-case/socket/socket-message-update-use-case.service.ts @@ -1,6 +1,8 @@ import { Injectable } from '@angular/core'; import { MessageLocalDataSourceService } from '../../../data/data-source/message/message-local-data-source.service'; -import { MessageOutPutDataDTO } from '../../../data/dto/message/messageOutputDTO'; +import { MessageOutPutDataDTO, MessageOutPutDataDTOSchema } from '../../../data/dto/message/messageOutputDTO'; +import { SafeValidateSchema, ValidateSchema } from 'src/app/services/decorators/validate-schema.decorator'; +import { MessageInputDTOSchema } from '../../../data/dto/message/messageInputDtO'; @Injectable({ providedIn: 'root' @@ -12,6 +14,7 @@ export class SocketMessageUpdateUseCaseService { ) { } + @SafeValidateSchema(MessageOutPutDataDTOSchema, 'SocketMessageUpdateUseCaseService') async execute(data: MessageOutPutDataDTO) { const result = await this.messageLocalDataSourceService.messageExist({id: data.id}) @@ -23,7 +26,7 @@ export class SocketMessageUpdateUseCaseService { // delete data.chatRoomId if(result.isOk()) { - console.log('message exist', result.value) + console.log('message exist', result.value, incomingMessage) return this.messageLocalDataSourceService.update(result.value.$id, incomingMessage) } else { console.log('message else') diff --git a/src/app/module/chat/infra/database/dexie/schema/message.ts b/src/app/module/chat/infra/database/dexie/schema/message.ts index 504c3a10e..9eceef4ec 100644 --- a/src/app/module/chat/infra/database/dexie/schema/message.ts +++ b/src/app/module/chat/infra/database/dexie/schema/message.ts @@ -5,7 +5,7 @@ export const MessageTable = z.object({ $id: z.number().optional(), id: z.string().optional(), roomId: z.string().uuid(), - message: z.string(), + message: z.string().nullable(), messageType: z.number(), canEdit: z.boolean(), oneShot: z.boolean(), diff --git a/src/app/pages/chat/messages/messages.page.html b/src/app/pages/chat/messages/messages.page.html index d0572fba5..f17e4bf25 100644 --- a/src/app/pages/chat/messages/messages.page.html +++ b/src/app/pages/chat/messages/messages.page.html @@ -1,4 +1,4 @@ - +
@@ -9,10 +9,10 @@
-
- {{ChatSystemService.getDmRoom(roomId).name}} - +
+ {{ roomData.roomName }} +
@@ -42,219 +42,102 @@ - -
+ -
-
-
- {{msg.u.name}} - {{msg.time}} -
+
+ +
+
+ +
-
- -
{{msg.msg}}
- - Apagou a mensagem - - - - - Enviado - - - - - Lido -
Tentar
-
-
- {{last ? scrollToBottom() : ''}} + {{ message.message }}
-
-
-
-
- {{msg.u.name}} - {{msg.time}} +
+
+ + + + + +
-
-
-
-
-
- - - {{"Imagem"}} - - - - -
- image - - - Enviado - - - - - Lido -
Tentar
-
- -
-
-
-
- -
- - - - - {{ file.title}} - - - - - -
- -
- - - - - - - - - - {{file.title}} -
- -
-
-
- - - {{"Mensagem de voz"}} - - - - -
-
- -
-
- - {{file.description}} - - - - - - - - Enviado - - - - - Lido -
Tentar
-
- -
-
-
-
- {{last ? scrollToBottom() : ''}} -
-
-
- {{msg.u.name}} criou esta reunião
-
- - De {{showDateDuration(msg.file.start_date)}} a - {{showDateDuration(msg.file.end_date)}} -
- - - {{msg.file.venue}} -
+
-
- Apagou a mensagem +
A enviar
+
Enviado
+ +
+ + +
+ + {{ emoji }} +
+ +
+ + {{ reaction.reaction }} + +
+
+
+ + + + + + +
+ +
+ + + + + - + -
+
{{durationDisplay}}
- - -
- \ No newline at end of file + diff --git a/src/app/pages/chat/messages/messages.page.scss b/src/app/pages/chat/messages/messages.page.scss index 3a2ac64b1..d713867cf 100644 --- a/src/app/pages/chat/messages/messages.page.scss +++ b/src/app/pages/chat/messages/messages.page.scss @@ -416,3 +416,81 @@ button::-moz-focus-inner { width: 111px !important; text-align: center; } + + +.message-item-options { + position: relative; +} + +.emoji-picker { + display: flex; + flex-wrap: wrap; + background: white; + border: 1px solid #ccc; + padding: 5px; + border-radius: 5px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + -ms-border-radius: 5px; + -o-border-radius: 5px; +} + +.emoji-icon { + font-size: 20px; + cursor: pointer; + margin: 2px; +} + + + +.messages { + font-size: rem(13); + font-family: Roboto; + overflow: auto; + + //set scroll do bottom + // position: absolute; + // top: 0; + // left: 0; + // overflow-x: hidden; + // overflow-y: auto; + // width: 100%; + // height: 100%; + // word-wrap: break-word; + // -webkit-overflow-scrolling: touch; + + .other-message, + .my-message { + + .message-container { + padding: 15px 20px; + margin: 10px 20px 10px 75px; + background: var(--chat-incoming-msg-color); + border-radius: 10px; + } + } + + .other-message { + display: flex; + /* justify-content: flex-end; */ + align-items: start; + flex-direction: column; + // float: left; + // Styles for incoming messages from other users + justify-content: flex-start; + .message-container { + padding: 15px 20px; + margin: 10px 75px 10px 20px; + background: #ebebeb; + border-radius: 10px; + } + } +} + +.my-message { + + display: flex; + /* justify-content: flex-end; */ + align-items: end; + flex-direction: column; +} diff --git a/src/app/pages/chat/messages/messages.page.ts b/src/app/pages/chat/messages/messages.page.ts index 623b6dd3f..364b5e0cc 100644 --- a/src/app/pages/chat/messages/messages.page.ts +++ b/src/app/pages/chat/messages/messages.page.ts @@ -37,6 +37,21 @@ import { RochetChatConnectorService } from 'src/app/services/chat/rochet-chat-co import { FileValidatorService } from "src/app/services/file/file-validator.service" import { sanitize } from "sanitize-filename-ts"; import { FilePicker } from '@capawesome/capacitor-file-picker'; +//====== +import { Observable as DexieObservable } from 'Dexie'; +import { Observable, Subscription } from 'rxjs'; +import { MessageRepositoryService } from 'src/app/module/chat/data/repository/message-respository.service' +import { RoomRepositoryService } from 'src/app/module/chat/data/repository/room-repository.service' +import { MessageTable } from 'src/app/module/chat/infra/database/dexie/schema/message'; +import { MessageInputDTO } from 'src/app/module/chat/data/dto/message/messageInputDtO'; +import { RoomListItemOutPutDTO } from 'src/app/module/chat/data/dto/room/roomListOutputDTO'; +import { UserTypingServiceRepository } from 'src/app/module/chat/data/repository/user-typing-repository.service'; +import { ChatServiceService } from 'src/app/module/chat/domain/chat-service.service'; +import { EditMessagePage } from 'src/app/modals/edit-message/edit-message.page'; +import { tap } from 'rxjs/operators'; +import { MessageEntity } from 'src/app/module/chat/domain/entity/message'; +import { MemberTable } from 'src/app/module/chat/infra/database/dexie/schema/members'; +import { TypingTable } from 'src/app/module/chat/infra/database/dexie/schema/typing'; @@ -104,6 +119,18 @@ export class MessagesPage implements OnInit, AfterViewInit, OnDestroy { audioPermissionStatus: 'granted' | 'denied' | 'prompt' | null = null sessionStore = SessionStore + roomData$: DexieObservable + roomStatus$: DexieObservable + roomMessage$: DexieObservable + roomMembers$: DexieObservable + //userTyping$: DexieObservable + userTyping$: TypingTable[] | undefined + newMessagesStream!: Subscription + + selectedMessage: any = null; + emojis: string[] = ['😊', '😂', '❤️', '👍', '😢']; // Add more emojis as needed + textField = '' + constructor( public popoverController: PopoverController, private modalController: ModalController, @@ -124,31 +151,54 @@ export class MessagesPage implements OnInit, AfterViewInit, OnDestroy { private router: Router, public RochetChatConnectorService: RochetChatConnectorService, private FileValidatorService: FileValidatorService, + /// + private roomRepositoryService: RoomRepositoryService, + private messageRepositoryService: MessageRepositoryService, + private userTypingServiceRepository: UserTypingServiceRepository, + private chatServiceService: ChatServiceService ) { - try { - this.loggedUser = SessionStore.user.ChatData['data']; - this.roomId = this.navParams.get('roomId'); + this.roomId = this.navParams.get('roomId'); - window.onresize = (event) => { - if (window.innerWidth > 701) { - this.modalController.dismiss(); - } - } + this.roomData$ = this.roomRepositoryService.getItemByIdLive(this.roomId) + this.roomMessage$ = this.messageRepositoryService.getItemsLive(this.roomId) - this.ChatSystemService.getDmRoom(this.roomId).loadHistory({}) - this.ChatSystemService.getDmRoom(this.roomId).scrollDown = this.scrollToBottomClicked - this.ChatSystemService.openRoom(this.roomId) + this.roomMembers$ = this.roomRepositoryService.getRoomMemberByIdLive(this.roomId) as any + this.roomStatus$ = this.roomRepositoryService.getRoomStatus(this.roomId) + this.roomRepositoryService.getRoomById(this.roomId) + this.messageRepositoryService.listAllMessagesByRoomId(this.roomId) + + this.userTypingServiceRepository.getUserTypingLive().subscribe((e) => { + const arrayNames = e.map(e => e.userName) + this.userTyping$ = e as any + + const uniqueArray = [...new Set(arrayNames)]; + + //(this.myInputRef.nativeElement as HTMLDivElement).innerHTML = '::'+ uniqueArray + }) + + this.newMessagesStream?.unsubscribe() + this.newMessagesStream = this.messageRepositoryService.subscribeToNewMessages(this.roomId).subscribe((e) => { setTimeout(() => { this.scrollToBottomClicked() - }, 150) - } catch (error) { - //alert(error) - } + }, 200) + + setTimeout(() => { + this.scrollToBottomClicked() + }, 500) + + }) + + //this.userTyping$ = this.userTypingMemoryDataSource.select(state => state) as any + + // let a = this.userTypingMemoryDataSource.select(state => state).subscribe((e) => { + // this.userTyping$ = e as any + // }) + } @@ -1336,6 +1386,67 @@ export class MessagesPage implements OnInit, AfterViewInit, OnDestroy { return blob; } + + messageDelete({messageId}) { + // this.messageRepositoryService.sendMessageDelete() + console.log('messageId', messageId) + this.chatServiceService.messageDelete({ + messageId: messageId, + roomId: this.roomId, + }) + } + + async editMessage(message: any) { + + const modal = await this.modalController.create({ + component: EditMessagePage, + cssClass: '', + componentProps: { + message: message.message, + roomId: this.roomId, + } + }); + + modal.present() + + return modal.onDidDismiss().then((res) => { + + this.chatServiceService.updateMessage({ + memberId: SessionStore.user.UserId, + message: res.data.message, + messageId: message.id, + requestId: '', + roomId: this.roomId + }) + }); + } + + toggleEmojiPicker(message: any) { + if (this.selectedMessage === message) { + this.selectedMessage = null; // Close the picker if it's already open + } else { + this.selectedMessage = message; // Open the picker for the selected message + } + } + + addReaction(message: any, emoji: string) { + // Logic to add reaction to the message + console.log(`Reacting to message ${message.id} with emoji ${emoji.codePointAt(0).toString(16)}`); + this.selectedMessage = null; // Close the picker after adding reaction + + this.chatServiceService.reactToMessage({ + memberId: SessionStore.user.UserId, + messageId: message.id, + roomId: this.roomId, + reaction: emoji, + requestId: '' + }) + + } + + sendTyping() { + this.userTypingServiceRepository.addUserTyping(this.roomId) + } } diff --git a/src/app/services/decorators/api-validate-schema.decorator.ts b/src/app/services/decorators/api-validate-schema.decorator.ts index 3e7ddaa99..f2990a1a3 100644 --- a/src/app/services/decorators/api-validate-schema.decorator.ts +++ b/src/app/services/decorators/api-validate-schema.decorator.ts @@ -20,8 +20,8 @@ export function APIReturn(schema: z.ZodTypeAny, context: string) { if (error instanceof ZodError) { // If validation fails, throw an error with the details // - ColoredLoggerService.error(error.errors, 'API unexpected data structure '+ context, schema._def.description) - + ColoredLoggerService.error(error.errors, 'API unexpected data structure '+ context) + console.error(result.value) // Capture the Zod validation error with additional context Sentry.withScope((scope) => { scope.setTag('APIReturn', 'user'); diff --git a/src/app/services/decorators/validate-schema.decorator.ts b/src/app/services/decorators/validate-schema.decorator.ts index 9e1edaaa0..ae43d5a64 100644 --- a/src/app/services/decorators/validate-schema.decorator.ts +++ b/src/app/services/decorators/validate-schema.decorator.ts @@ -64,6 +64,7 @@ export function SafeValidateSchema(schema: Schema, context: string) { tracing?.setAttribute?.('map.error.schema-'+i, JSON.stringify(schema)) } ColoredLoggerService.error(e.errors, 'socket unexpected data structure '+ context, schema._def.description) + console.error(args[0]) } return originalMethod.apply(this, args); diff --git a/src/app/shared/chat/messages/messages.page.html b/src/app/shared/chat/messages/messages.page.html index d6bc77717..7df76e47d 100644 --- a/src/app/shared/chat/messages/messages.page.html +++ b/src/app/shared/chat/messages/messages.page.html @@ -58,7 +58,7 @@
- + diff --git a/src/app/shared/chat/messages/messages.page.ts b/src/app/shared/chat/messages/messages.page.ts index e3caab98b..9d52945eb 100644 --- a/src/app/shared/chat/messages/messages.page.ts +++ b/src/app/shared/chat/messages/messages.page.ts @@ -993,7 +993,6 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy messageDelete({messageId}) { // this.messageRepositoryService.sendMessageDelete() - this.chatServiceService.messageDelete({ messageId: messageId, roomId: this.roomId,