Skip to content

Commit dbcd952

Browse files
committed
fix: improve error handling in message handlers
1 parent 4bf19ea commit dbcd952

File tree

2 files changed

+64
-19
lines changed

2 files changed

+64
-19
lines changed

src/modules/GroupChannel/context/GroupChannelProvider.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import { getIsReactionEnabled } from '../../../utils/getIsReactionEnabled';
2929

3030
export { ThreadReplySelectType } from './const'; // export for external usage
3131

32-
type OnBeforeHandler<T> = (params: T) => T | Promise<T>;
32+
export type OnBeforeHandler<T> = (params: T) => T | Promise<T> | void | Promise<void>;
3333
type MessageListQueryParamsType = Omit<MessageCollectionParams, 'filter'> & MessageFilterParams;
3434
type MessageActions = ReturnType<typeof useMessageActions>;
3535
type MessageListDataSourceWithoutActions = Omit<ReturnType<typeof useGroupChannelMessages>, keyof MessageActions | `_dangerous_${string}`>;

src/modules/GroupChannel/context/hooks/useMessageActions.ts

Lines changed: 63 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { match } from 'ts-pattern';
12
import { useCallback } from 'react';
23
import { useGroupChannelMessages } from '@sendbird/uikit-tools';
34
import { MessageMetaArray } from '@sendbird/chat/message';
@@ -19,9 +20,10 @@ import {
1920
VOICE_MESSAGE_FILE_NAME,
2021
VOICE_MESSAGE_MIME_TYPE,
2122
} from '../../../../utils/consts';
22-
import type { SendableMessageType } from '../../../../utils';
23+
import type { SendableMessageType, CoreMessageType } from '../../../../utils';
2324
import type { ReplyType } from '../../../../types';
24-
import type { GroupChannelProviderProps } from '../GroupChannelProvider';
25+
import type { GroupChannelProviderProps, OnBeforeHandler } from '../GroupChannelProvider';
26+
import useSendbirdStateContext from '../../../../hooks/useSendbirdStateContext';
2527

2628
type MessageListDataSource = ReturnType<typeof useGroupChannelMessages>;
2729
type MessageActions = {
@@ -39,6 +41,13 @@ interface Params extends GroupChannelProviderProps, MessageListDataSource {
3941
}
4042

4143
const pass = <T>(value: T) => value;
44+
type MessageParamsByType = {
45+
user: UserMessageCreateParams;
46+
file: FileMessageCreateParams;
47+
multipleFiles: MultipleFilesMessageCreateParams;
48+
voice: FileMessageCreateParams;
49+
update: UserMessageUpdateParams;
50+
};
4251

4352
/**
4453
* @description This hook controls common processes related to message sending, updating.
@@ -60,7 +69,7 @@ export function useMessageActions(params: Params): MessageActions {
6069
quoteMessage,
6170
replyType,
6271
} = params;
63-
72+
const { eventHandlers } = useSendbirdStateContext();
6473
const buildInternalMessageParams = useCallback(
6574
<T extends BaseMessageCreateParams>(basicParams: T): T => {
6675
const messageParams = { ...basicParams } as T;
@@ -84,33 +93,71 @@ export function useMessageActions(params: Params): MessageActions {
8493
[],
8594
);
8695

96+
const processParams = useCallback(async <T extends keyof MessageParamsByType>(
97+
handler: OnBeforeHandler<MessageParamsByType[T]>,
98+
params: ReturnType<typeof buildInternalMessageParams>,
99+
type: keyof MessageParamsByType,
100+
): Promise<MessageParamsByType[T]> => {
101+
try {
102+
const result = await handler(params as MessageParamsByType[T]);
103+
return (result === undefined ? params : result) as MessageParamsByType[T];
104+
} catch (error) {
105+
if (typeof eventHandlers?.message === 'object') {
106+
match(type)
107+
.with('file', 'voice', () => {
108+
if ((params as any).file) {
109+
eventHandlers.message.onFileUploadFailed?.(error);
110+
}
111+
eventHandlers.message.onSendMessageFailed?.(params as CoreMessageType, error);
112+
})
113+
.with('multipleFiles', () => {
114+
if ((params as MultipleFilesMessageCreateParams).fileInfoList) {
115+
eventHandlers.message.onFileUploadFailed?.(error);
116+
}
117+
eventHandlers.message.onSendMessageFailed?.(params as CoreMessageType, error);
118+
})
119+
.with('user', () => {
120+
eventHandlers.message.onSendMessageFailed?.(
121+
params as CoreMessageType,
122+
error,
123+
);
124+
})
125+
.with('update', () => {
126+
eventHandlers.message.onUpdateMessageFailed?.(
127+
params as CoreMessageType,
128+
error,
129+
);
130+
})
131+
.exhaustive();
132+
}
133+
throw error;
134+
}
135+
}, [eventHandlers]);
136+
87137
return {
88138
sendUserMessage: useCallback(
89139
async (params) => {
90140
const internalParams = buildInternalMessageParams<UserMessageCreateParams>(params);
91-
const processedParams = await onBeforeSendUserMessage(internalParams);
92-
141+
const processedParams = await processParams(onBeforeSendUserMessage, internalParams, 'user') as UserMessageCreateParams;
93142
return sendUserMessage(processedParams, asyncScrollToBottom);
94143
},
95-
[buildInternalMessageParams, sendUserMessage, scrollToBottom],
144+
[buildInternalMessageParams, sendUserMessage, scrollToBottom, processParams],
96145
),
97146
sendFileMessage: useCallback(
98147
async (params) => {
99148
const internalParams = buildInternalMessageParams<FileMessageCreateParams>(params);
100-
const processedParams = await onBeforeSendFileMessage(internalParams);
101-
149+
const processedParams = await processParams(onBeforeSendFileMessage, internalParams, 'file') as FileMessageCreateParams;
102150
return sendFileMessage(processedParams, asyncScrollToBottom);
103151
},
104-
[buildInternalMessageParams, sendFileMessage, scrollToBottom],
152+
[buildInternalMessageParams, sendFileMessage, scrollToBottom, processParams],
105153
),
106154
sendMultipleFilesMessage: useCallback(
107155
async (params) => {
108156
const internalParams = buildInternalMessageParams<MultipleFilesMessageCreateParams>(params);
109-
const processedParams = await onBeforeSendMultipleFilesMessage(internalParams);
110-
157+
const processedParams = await processParams(onBeforeSendMultipleFilesMessage, internalParams, 'multipleFiles') as MultipleFilesMessageCreateParams;
111158
return sendMultipleFilesMessage(processedParams, asyncScrollToBottom);
112159
},
113-
[buildInternalMessageParams, sendMultipleFilesMessage, scrollToBottom],
160+
[buildInternalMessageParams, sendMultipleFilesMessage, scrollToBottom, processParams],
114161
),
115162
sendVoiceMessage: useCallback(
116163
async (params: FileMessageCreateParams, duration: number) => {
@@ -129,20 +176,18 @@ export function useMessageActions(params: Params): MessageActions {
129176
}),
130177
],
131178
});
132-
const processedParams = await onBeforeSendVoiceMessage(internalParams);
133-
179+
const processedParams = await processParams(onBeforeSendVoiceMessage, internalParams, 'voice');
134180
return sendFileMessage(processedParams, asyncScrollToBottom);
135181
},
136-
[buildInternalMessageParams, sendFileMessage, scrollToBottom],
182+
[buildInternalMessageParams, sendFileMessage, scrollToBottom, processParams],
137183
),
138184
updateUserMessage: useCallback(
139185
async (messageId: number, params: UserMessageUpdateParams) => {
140186
const internalParams = buildInternalMessageParams<UserMessageUpdateParams>(params);
141-
const processedParams = await onBeforeUpdateUserMessage(internalParams);
142-
187+
const processedParams = await processParams(onBeforeUpdateUserMessage, internalParams, 'update');
143188
return updateUserMessage(messageId, processedParams);
144189
},
145-
[buildInternalMessageParams, updateUserMessage],
190+
[buildInternalMessageParams, updateUserMessage, processParams],
146191
),
147192
};
148193
}

0 commit comments

Comments
 (0)