diff --git a/src/components/Channel/utils.ts b/src/components/Channel/utils.ts deleted file mode 100644 index d37332ea8..000000000 --- a/src/components/Channel/utils.ts +++ /dev/null @@ -1,164 +0,0 @@ -import { - type APIErrorResponse, - type ChannelState, - type MessageResponse, - StreamAPIError, -} from 'stream-chat'; - -/** - * Utility function for jumpToFirstUnreadMessage - * @param targetId - * @param msgSet - */ -export const findInMsgSetById = ( - targetId: string, - msgSet: ReturnType[], -) => { - for (let i = msgSet.length - 1; i >= 0; i--) { - const item = msgSet[i]; - if (item.id === targetId) { - return { - index: i, - target: item, - }; - } - } - return { - index: -1, - }; -}; - -/** - * Utility function for jumpToFirstUnreadMessage - * @param targetDate - * @param msgSet - * @param exact - */ -export const findInMsgSetByDate = ( - targetDate: Date, - msgSet: MessageResponse[] | ReturnType[], - exact = false, -) => { - const targetTimestamp = targetDate.getTime(); - let left = 0; - let middle = 0; - let right = msgSet.length - 1; - while (left <= right) { - middle = Math.floor((right + left) / 2); - const middleTimestamp = new Date( - msgSet[middle].created_at as string | Date, - ).getTime(); - const middleLeftTimestamp = - msgSet[middle - 1]?.created_at && - new Date(msgSet[middle - 1].created_at as string | Date).getTime(); - const middleRightTimestamp = - msgSet[middle + 1]?.created_at && - new Date(msgSet[middle + 1].created_at as string | Date).getTime(); - if ( - middleTimestamp === targetTimestamp || - (middleLeftTimestamp && - middleRightTimestamp && - middleLeftTimestamp < targetTimestamp && - targetTimestamp < middleRightTimestamp) - ) { - return { index: middle, target: msgSet[middle] }; - } - if (middleTimestamp < targetTimestamp) left = middle + 1; - else right = middle - 1; - } - - if ( - !exact || - new Date(msgSet[left].created_at as string | Date).getTime() === targetTimestamp - ) { - return { index: left, target: msgSet[left] }; - } - return { index: -1 }; -}; -/** - * Compatibility adapter: - * LocalMessage.error expects StreamAPIError, but some transport failures - * (for example Axios ERR_NETWORK while offline) do not have an HTTP response payload. - */ -export const adaptMessageSendErrorToErrorFromResponse = ( - error: unknown, -): StreamAPIError => { - if (error instanceof StreamAPIError) { - return error; - } - - const fallbackMessage = error instanceof Error ? error.message : 'Message send failed'; - let message = fallbackMessage; - let status = 0; - let code: number | undefined; - - if (typeof error === 'object' && error !== null) { - const maybeAxiosError = error as { - code?: unknown; - message?: unknown; - name?: unknown; - response?: StreamAPIError['response']; - status?: unknown; - }; - - if (maybeAxiosError.name === 'AxiosError' && maybeAxiosError.code === 'ERR_NETWORK') { - message = - typeof maybeAxiosError.message === 'string' - ? maybeAxiosError.message - : 'Network Error'; - status = maybeAxiosError.response?.status ?? 0; - - return new StreamAPIError(message, { - code: undefined, - response: - maybeAxiosError.response ?? - ({ - // Compatibility shim: this is an intentionally incomplete AxiosResponse-like object. - data: { - duration: '', - message, - more_info: '', - StatusCode: status, - }, - status, - } as StreamAPIError['response']), - status, - }); - } - - try { - // error response isn't usable so needs to be stringified then parsed - const stringError = JSON.stringify(error); - const parsedError = stringError - ? (JSON.parse(stringError) as Record) - : {}; - - if (typeof parsedError.message === 'string') { - message = parsedError.message; - } - if (typeof parsedError.status === 'number') { - status = parsedError.status; - } - if (typeof parsedError.code === 'number') { - code = parsedError.code; - } - } catch { - // keep fallback values - } - } - - return new StreamAPIError(message, { - code, - response: { - // Compatibility shim: this is an intentionally incomplete AxiosResponse-like object. - data: { - duration: '', - message, - more_info: '', - StatusCode: status, - }, - status, - } as StreamAPIError['response'], - status, - }); -}; diff --git a/src/components/Thread/Thread.tsx b/src/components/Thread/Thread.tsx index 6064a96c5..98bd4264f 100644 --- a/src/components/Thread/Thread.tsx +++ b/src/components/Thread/Thread.tsx @@ -24,9 +24,9 @@ import type { MessageProps, MessageUIComponentProps } from '../Message/types'; import type { MessageActionsArray } from '../Message/utils'; import type { DeleteMessageOptions, - EventAPIResponse, LocalMessage, MarkReadRequest, + MarkReadResponseEvent, MessageRequest, MessageResponse, SendMessageOptions, @@ -66,7 +66,7 @@ export type ThreadProps = { doMarkReadRequest?: (params: { thread: StreamThread; options?: MarkReadRequest; - }) => Promise | void; + }) => Promise<{ event: MarkReadResponseEvent } | null> | void; /** Custom action handler to override the default `channel.sendMessage` request function in thread flows */ doSendMessageRequest?: ( thread: StreamThread, diff --git a/src/components/Thread/hooks/useThreadRequestHandlers.ts b/src/components/Thread/hooks/useThreadRequestHandlers.ts index b1145117b..60519a50b 100644 --- a/src/components/Thread/hooks/useThreadRequestHandlers.ts +++ b/src/components/Thread/hooks/useThreadRequestHandlers.ts @@ -2,9 +2,9 @@ import { useEffect } from 'react'; import { localMessageToNewMessagePayload } from 'stream-chat'; import type { DeleteMessageOptions, - EventAPIResponse, LocalMessage, MarkReadRequest, + MarkReadResponseEvent, MessageRequest, MessageResponse, SendMessageOptions, @@ -24,7 +24,7 @@ export type ThreadRequestHandlersParams = { doMarkReadRequest?: (params: { thread: StreamThread; options?: MarkReadRequest; - }) => Promise | void; + }) => Promise<{ event: MarkReadResponseEvent } | null> | void; doSendMessageRequest?: ( thread: StreamThread, message: MessageRequest,