Skip to content

Commit dc7a990

Browse files
committed
feat: emit message in messageUpdate output
1 parent 1e91aba commit dc7a990

File tree

6 files changed

+91
-42
lines changed

6 files changed

+91
-42
lines changed

projects/stream-chat-angular/src/lib/channel.service.spec.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1256,7 +1256,14 @@ describe('ChannelService', () => {
12561256
true
12571257
);
12581258

1259-
expect(latestMessage.status).toBe('sending');
1259+
expect(channel.state.addMessageSorted).toHaveBeenCalledWith(
1260+
jasmine.objectContaining({
1261+
status: 'received',
1262+
}),
1263+
true
1264+
);
1265+
1266+
expect(latestMessage.status).toBe('received');
12601267
});
12611268

12621269
it('should set message state while sending', async () => {

projects/stream-chat-angular/src/lib/channel.service.thread.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,7 @@ describe('ChannelService - threads', () => {
548548
service.activeChannel$.pipe(first()).subscribe((c) => (channel = c!));
549549
const parentMessage = mockMessage();
550550
parentMessage.id = 'parentId';
551-
const replies = [mockMessage(), mockMessage()];
551+
const replies = [mockMessage(1), mockMessage(2)];
552552
replies.forEach((r) => (r.parent_id = parentMessage.id));
553553
channel.state.threads[parentMessage.id] = replies;
554554
spyOn(channel, 'getReplies').and.resolveTo({

projects/stream-chat-angular/src/lib/channel.service.ts

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
ReplaySubject,
77
Subscription,
88
} from 'rxjs';
9-
import { first, map, shareReplay } from 'rxjs/operators';
9+
import { first, map, shareReplay, take } from 'rxjs/operators';
1010
import {
1111
Attachment,
1212
Channel,
@@ -677,7 +677,8 @@ export class ChannelService<
677677
const channel = this.activeChannelSubject.getValue()!;
678678
preview.readBy = [];
679679
channel.state.addMessageSorted(preview, true);
680-
await this.sendMessageRequest(preview, customData);
680+
const response = await this.sendMessageRequest(preview, customData);
681+
return response;
681682
}
682683

683684
/**
@@ -704,9 +705,15 @@ export class ChannelService<
704705
async updateMessage(message: StreamMessage<T>) {
705706
const messageToUpdate = { ...message };
706707
delete messageToUpdate.i18n;
707-
await this.chatClientService.chatClient.updateMessage(
708+
const response = await this.chatClientService.chatClient.updateMessage(
708709
messageToUpdate as any as UpdatedMessage<T>
709710
);
711+
712+
const channel = this.channelsSubject
713+
.getValue()
714+
?.find((c) => c.cid === message.cid);
715+
716+
return this.transformToStreamMessage(response.message, channel);
710717
}
711718

712719
/**
@@ -879,20 +886,24 @@ export class ChannelService<
879886
quoted_message_id: preview.quoted_message_id,
880887
...customData,
881888
} as Message<T>); // TODO: find out why we need typecast here
882-
if (response?.message) {
883-
channel.state.addMessageSorted(
884-
{
885-
...response.message,
886-
status: 'received',
887-
},
888-
true
889-
);
890-
isThreadReply
891-
? this.activeThreadMessagesSubject.next([
892-
...channel.state.threads[preview.parent_id!],
893-
])
894-
: this.activeChannelMessagesSubject.next([...channel.state.messages]);
895-
}
889+
channel.state.addMessageSorted(
890+
{
891+
...response.message,
892+
status: 'received',
893+
},
894+
true
895+
);
896+
isThreadReply
897+
? this.activeThreadMessagesSubject.next([
898+
...channel.state.threads[preview.parent_id!],
899+
])
900+
: this.activeChannelMessagesSubject.next([...channel.state.messages]);
901+
let messages!: StreamMessage<T>[];
902+
(isThreadReply ? this.activeThreadMessages$ : this.activeChannelMessages$)
903+
.pipe(take(1))
904+
.subscribe((m) => (messages = m));
905+
const newMessage = messages[messages.length - 1]!;
906+
return newMessage;
896907
} catch (error) {
897908
const stringError = JSON.stringify(error);
898909
const parsedError: { status?: number } = stringError
@@ -912,6 +923,12 @@ export class ChannelService<
912923
...channel.state.threads[preview.parent_id!],
913924
])
914925
: this.activeChannelMessagesSubject.next([...channel.state.messages]);
926+
let messages!: StreamMessage<T>[];
927+
(isThreadReply ? this.activeThreadMessages$ : this.activeChannelMessages$)
928+
.pipe(take(1))
929+
.subscribe((m) => (messages = m));
930+
const newMessage = messages[messages.length - 1]!;
931+
return newMessage;
915932
}
916933
}
917934

@@ -1521,7 +1538,7 @@ export class ChannelService<
15211538

15221539
private transformToStreamMessage(
15231540
message: StreamMessage<T> | MessageResponse<T> | FormatMessageResponse<T>,
1524-
channel: Channel<T>
1541+
channel?: Channel<T>
15251542
) {
15261543
const isThreadMessage = !!message.parent_id;
15271544
if (
@@ -1555,7 +1572,11 @@ export class ChannelService<
15551572
if (this.isFormatMessageResponse(message)) {
15561573
return {
15571574
...message,
1558-
readBy: isThreadMessage ? [] : getReadBy(message, channel),
1575+
readBy: isThreadMessage
1576+
? []
1577+
: channel
1578+
? getReadBy(message, channel)
1579+
: [],
15591580
translation: getMessageTranslation(
15601581
message,
15611582
channel,
@@ -1566,7 +1587,11 @@ export class ChannelService<
15661587
const formatMessage = this.formatMessage(message);
15671588
return {
15681589
...formatMessage,
1569-
readBy: isThreadMessage ? [] : getReadBy(formatMessage, channel),
1590+
readBy: isThreadMessage
1591+
? []
1592+
: channel
1593+
? getReadBy(formatMessage, channel)
1594+
: [],
15701595
translation: getMessageTranslation(
15711596
message,
15721597
channel,

projects/stream-chat-angular/src/lib/message-input/message-input.component.spec.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,9 +238,12 @@ describe('MessageInputComponent', () => {
238238
fixture.detectChanges();
239239
const spy = jasmine.createSpy();
240240
component.messageUpdate.subscribe(spy);
241+
updateMessageSpy.and.resolveTo({ id: component.message.id });
241242
await component.messageSent();
242243

243-
expect(spy).toHaveBeenCalledWith(undefined);
244+
expect(spy).toHaveBeenCalledWith({
245+
message: jasmine.objectContaining({ id: component.message.id }),
246+
});
244247
});
245248

246249
it('should send message if button is clicked', () => {

projects/stream-chat-angular/src/lib/message-input/message-input.component.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,9 @@ export class MessageInputComponent
9090
/**
9191
* Emits when a message was successfuly sent or updated
9292
*/
93-
@Output() readonly messageUpdate = new EventEmitter<void>();
93+
@Output() readonly messageUpdate = new EventEmitter<{
94+
message: StreamMessage;
95+
}>();
9496
@HostBinding() class = 'str-chat__message-input-angular-host';
9597
isFileUploadAuthorized: boolean | undefined;
9698
canSendLinks: boolean | undefined;
@@ -353,7 +355,7 @@ export class MessageInputComponent
353355
this.textareaValue = '';
354356
}
355357
try {
356-
await (this.isUpdate
358+
const message = await (this.isUpdate
357359
? this.channelService.updateMessage({
358360
...this.message!,
359361
text: text,
@@ -366,7 +368,7 @@ export class MessageInputComponent
366368
this.parentMessageId,
367369
this.quotedMessage?.id
368370
));
369-
this.messageUpdate.emit();
371+
this.messageUpdate.emit({ message });
370372
if (!this.isUpdate) {
371373
this.attachmentService.resetAttachmentUploads();
372374
}

projects/stream-chat-angular/src/lib/mocks/index.ts

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ export const mockCurrentUser = () =>
2121
image: 'link/to/photo',
2222
} as UserResponse<DefaultStreamChatGenerics>);
2323

24-
export const mockMessage = () =>
24+
export const mockMessage = (id?: number) =>
2525
({
26-
id: 'id',
26+
id: id === undefined ? 'id' : `id${id}`,
2727
text: 'Hello from Angular SDK',
2828
user: mockCurrentUser(),
2929
type: 'regular',
@@ -84,7 +84,10 @@ export const generateMockChannels = (length = 25) => {
8484
},
8585
watch: () => {},
8686
stopWatching: () => {},
87-
sendMessage: () => {},
87+
sendMessage: (m: any) => {
88+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
89+
return Promise.resolve({ message: m });
90+
},
8891
sendImage: () => {},
8992
sendFile: () => {},
9093
sendAction: () => {},
@@ -113,22 +116,31 @@ export const generateMockChannels = (length = 25) => {
113116
eddie: { user: { id: 'eddie' } },
114117
},
115118
addMessageSorted: function (response: MessageResponse) {
116-
if (response.parent_id) {
117-
if (
118-
(this.threads as { [key: string]: StreamMessage[] })[
119-
response.parent_id
120-
]
121-
) {
122-
(this.threads as { [key: string]: StreamMessage[] })[
123-
response.parent_id
124-
].push(response as any as StreamMessage);
119+
if (!response) {
120+
return;
121+
}
122+
let array: StreamMessage[];
123+
const message = response as any as StreamMessage;
124+
const threads = this.threads as { [key: string]: StreamMessage[] };
125+
if (message.parent_id) {
126+
if (threads[message.parent_id]) {
127+
array = threads[message.parent_id];
125128
} else {
126-
(this.threads as { [key: string]: StreamMessage[] })[
127-
response.parent_id
128-
] = [response as any as StreamMessage];
129+
array = [];
130+
threads[message.parent_id] = array;
129131
}
130132
} else {
131-
this.messages.push(response as any as StreamMessage);
133+
array = this.messages;
134+
}
135+
const existingMessageIndex = array.findIndex((m) =>
136+
message.id
137+
? m.id === message.id
138+
: m.created_at === message.created_at
139+
);
140+
if (existingMessageIndex === -1) {
141+
array.push(message);
142+
} else {
143+
array[existingMessageIndex] = message;
132144
}
133145
},
134146
removeMessage: () => {},

0 commit comments

Comments
 (0)