diff --git a/src/app/module/chat/data/async/list/rooms/messageListChangedetector.ts b/src/app/module/chat/data/async/list/rooms/messageListChangedetector.ts new file mode 100644 index 000000000..ca89048fd --- /dev/null +++ b/src/app/module/chat/data/async/list/rooms/messageListChangedetector.ts @@ -0,0 +1,34 @@ +import { TableRoom } from "../../../data-source/room/rooom-local-data-source.service"; +import { RoomListItemOutPutDTO, RoomListOutPutDTO } from "../../../dto/room/roomListOutputDTO"; + +export function messageListDetermineChanges(serverList: any[], localList: any[]) { + // Convert lists to dictionaries for easier comparison + const localDict = localList.reduce((acc, item) => { + acc[item.id] = item; + return acc; + }, {}); + + const serverDict = serverList.reduce((acc, item) => { + acc[item.id] = item; + return acc; + }, {}); + + // Identify added and deleted items + const addedItems = serverList.filter(item => !localDict[item.id]); + const deletedItems = localList.filter(item => !serverDict[item.id]); + + // Identify changed items + const changedItems = serverList.filter(item => { + const localItem = localDict[item.id]; + return localItem && (item.editedAt !== localItem.editedAt || item.reactions.some((r, index) => { + const localReaction = localItem.reactions[index]; + return !localReaction || r.reactedAt !== localReaction.reactedAt; + })); + }); + + return { + addedItems, + deletedItems, + changedItems + } +} diff --git a/src/app/module/chat/data/data-source/message/message-local-data-source.service.ts b/src/app/module/chat/data/data-source/message/message-local-data-source.service.ts index 75919fcb7..8c7970e01 100644 --- a/src/app/module/chat/data/data-source/message/message-local-data-source.service.ts +++ b/src/app/module/chat/data/data-source/message/message-local-data-source.service.ts @@ -2,7 +2,7 @@ import { Injectable } from '@angular/core'; import { Dexie, EntityTable, liveQuery } from 'Dexie'; import { err, ok, Result } from 'neverthrow'; import { z } from 'zod'; -import { Observable, Subject } from 'rxjs'; +import { from, Observable, Subject } from 'rxjs'; import { filter } from 'rxjs/operators'; import { MessageInputDTO } from '../../dto/message/messageInputDtO'; import { MessageEntity } from '../../../domain/entity/message'; @@ -24,7 +24,13 @@ const tableSchema = z.object({ wxeMail: z.string(), userPhoto: z.string(), }), - sending: z.boolean().optional() + sending: z.boolean().optional(), + reaction: z.object({ + id: z.string(), + reactedAt: z.string(), + reaction: z.string(), + sender: z.object({}), + }).array() }) export const IncomingMessageSchema = z.object({ @@ -67,11 +73,11 @@ export class MessageLocalDataSourceService { constructor() { - messageDataSource.message.hook('creating', (primKey, obj, trans) => { - // const newMessage = await trans.table('message').get(primKey); - this.messageSubject.next(obj); - // return newMessage - }) + // messageDataSource.message.hook('creating', (primKey, obj, trans) => { + // // const newMessage = await trans.table('message').get(primKey); + // this.messageSubject.next(obj); + // // return newMessage + // }) } @@ -110,6 +116,7 @@ export class MessageLocalDataSourceService { try { const result = await messageDataSource.message.add(data) + this.messageSubject.next({roomId: data.roomId}); return ok(result as string) } catch (e) { return err(false) @@ -128,6 +135,7 @@ export class MessageLocalDataSourceService { try { const result = await messageDataSource.message.add(data) + this.messageSubject.next({roomId: data.roomId}); return ok(result as string) } catch (e) { return err(false) @@ -161,6 +169,7 @@ export class MessageLocalDataSourceService { async update(data: TableMessage ) { try { + console.log('update images 22222') const result = await messageDataSource.message.update(data.$id, data) return ok(result) } catch (e) { @@ -173,6 +182,7 @@ export class MessageLocalDataSourceService { async updateByMessageId(data: TableMessage ) { try { + console.log('update sdfsdfsd') const result = await messageDataSource.message.update(data.id, data) return ok(result) } catch (e) { @@ -192,10 +202,12 @@ export class MessageLocalDataSourceService { } } + getItems(roomId: string) { + return messageDataSource.message.where('roomId').equals(roomId).toArray() + } + getItemsLive(roomId: string) { - return liveQuery(() => - messageDataSource.message.where('roomId').equals(roomId).sortBy('$id') - ) + return liveQuery(() => messageDataSource.message.where('roomId').equals(roomId).sortBy('$id')) } diff --git a/src/app/module/chat/data/repository/message-respository.service.ts b/src/app/module/chat/data/repository/message-respository.service.ts index 44456f694..951097877 100644 --- a/src/app/module/chat/data/repository/message-respository.service.ts +++ b/src/app/module/chat/data/repository/message-respository.service.ts @@ -9,6 +9,7 @@ import { v4 as uuidv4 } from 'uuid' import { err, ok } from 'neverthrow'; import { MessageDeleteInputDTO } from '../../domain/use-case/message-delete-live-use-case.service'; import { MessageUpdateInput } from '../../domain/use-case/message-update-use-case.service'; +import { messageListDetermineChanges } from '../async/list/rooms/messageListChangedetector'; export const InstanceId = uuidv4(); @@ -64,8 +65,8 @@ export class MessageRepositoryService { } // console.log({clone}) - console.log('update message') - return this.messageLocalDataSourceService.update({...clone, sending: false}) + console.log('update message 11111') + return this.messageLocalDataSourceService.update({...clone, sending: false, roomId: data.roomId}) return ok(true) } else { console.log('no message to upload') @@ -112,14 +113,23 @@ export class MessageRepositoryService { async listAllMessagesByRoomId(id: string) { const result = await this.messageRemoteDataSourceService.getMessagesFromRoom(id) + const localResult = await this.messageLocalDataSourceService.getItems(id) if(result.isOk()) { - for(const message of result.value.data) { + const { addedItems, changedItems } = messageListDetermineChanges(result.value.data, localResult) + + for(const message of changedItems) { let clone: TableMessage = message clone.roomId = id await this.messageLocalDataSourceService.findOrUpdate(clone) } + + for(const message of addedItems) { + let clone: TableMessage = message + clone.roomId = id + await this.messageLocalDataSourceService.createMessage(clone) + } } return result } diff --git a/src/app/module/chat/domain/entity/message.ts b/src/app/module/chat/domain/entity/message.ts index 56dcdd4c7..5e9e1bbd0 100644 --- a/src/app/module/chat/domain/entity/message.ts +++ b/src/app/module/chat/domain/entity/message.ts @@ -39,6 +39,7 @@ export class MessageEntity implements Message { userPhoto: string, } sending: boolean + sendAttemp = 0 constructor() {} diff --git a/src/app/shared/chat/messages/messages.page.html b/src/app/shared/chat/messages/messages.page.html index 1c67b6275..d6bc77717 100644 --- a/src/app/shared/chat/messages/messages.page.html +++ b/src/app/shared/chat/messages/messages.page.html @@ -41,27 +41,38 @@ -
+
+ *ngFor="let message of (roomMessage$ | async)" class="messages-list-item-wrapper" + [ngClass]="{'my-message': message.sender.wxUserId === sessionStore.user.UserId, 'other-message': message.sender.wxUserId !== sessionStore.user.UserId}" + >
- {{ message.message }} -
- - +
+
+ {{ message.message }} +
+ +
+
+ + + + + + +
+ +
-
- - - - - -
+
+
A enviar
+
Enviado
+ +
@@ -80,12 +91,12 @@
- + diff --git a/src/app/shared/chat/messages/messages.page.ts b/src/app/shared/chat/messages/messages.page.ts index a476bd2d5..b43ddd5b1 100644 --- a/src/app/shared/chat/messages/messages.page.ts +++ b/src/app/shared/chat/messages/messages.page.ts @@ -1,4 +1,4 @@ -import { AfterViewInit, Component, ElementRef, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges, ViewChild } from '@angular/core'; +import { AfterViewInit, Component, ElementRef, EventEmitter, HostListener, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges, ViewChild } from '@angular/core'; import { AnimationController, GestureController, IonRange, ModalController, PopoverController } from '@ionic/angular'; import { ToastService } from 'src/app/services/toast.service'; import { ChatOptionsPopoverPage } from 'src/app/shared/popover/chat-options-popover/chat-options-popover.page'; @@ -33,7 +33,7 @@ import { PermissionService } from 'src/app/services/permission.service'; import { FileValidatorService } from "src/app/services/file/file-validator.service" import { ChatPopoverPage } from '../../popover/chat-popover/chat-popover.page'; import { Observable as DexieObservable } from 'Dexie'; -import { Subscription } from 'rxjs'; +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 { TableMessage } from 'src/app/module/chat/data/data-source/message/message-local-data-source.service'; @@ -44,6 +44,7 @@ import { UserTypingServiceRepository } from 'src/app/module/chat/data/repository import { UserTypingList } from 'src/app/module/chat/data/data-source/userTyping/user-typing-local-data-source.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'; const IMAGE_DIR = 'stored-images'; @@ -131,8 +132,7 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy selectedMessage: any = null; emojis: string[] = ['😊', '😂', '❤️', '👍', '😢']; // Add more emojis as needed - - + totalMessage = 0 constructor( public popoverController: PopoverController, private modalController: ModalController, @@ -162,7 +162,9 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy ngOnChanges(changes: SimpleChanges): void { this.roomData$ = this.roomRepositoryService.getItemByIdLive(this.roomId) + this.roomMessage$ = this.messageRepositoryService.getItemsLive(this.roomId) + this.roomMembers$ = this.roomRepositoryService.getRoomMemberByIdLive(this.roomId) as any this.roomStatus$ = this.roomRepositoryService.getRoomStatus(this.roomId) this.roomRepositoryService.getRoomById(this.roomId) @@ -175,20 +177,18 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy const uniqueArray = [...new Set(arrayNames)]; (this.myInputRef.nativeElement as HTMLDivElement).innerHTML = '::'+ uniqueArray - this.scrollToBottomClicked() }) this.newMessagesStream?.unsubscribe() this.newMessagesStream = this.messageRepositoryService.subscribeToNewMessages(this.roomId).subscribe((e) => { - setTimeout(() => { - this.scrollToBottomClicked() - }, 10) setTimeout(() => { this.scrollToBottomClicked() }, 200) - console.log('new message==============') + setTimeout(() => { + this.scrollToBottomClicked() + }, 500) }) @@ -327,9 +327,21 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy } catch (err) { } } + + // @HostListener('scroll', ['$event']) + // onScroll(event: any): void { + // // const scrollTop = event.target.scrollTop; + // // const scrollHeight = event.target.scrollHeight; + // // const clientHeight = event.target.clientHeight; + + // // if (scrollTop === 0) { + // // console.log('load more') + // // } + // } + ngAfterViewInit() { - this.scrollChangeCallback = () => this.onContentScrolled(event); - window.addEventListener('scroll', this.scrollChangeCallback, true); + // this.scrollChangeCallback = () => this.onContentScrolled(event); + // window.addEventListener('scroll', this.scrollChangeCallback, true); } onContentScrolled(e) {