Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,6 @@
},
"resolutions": {
"@sendbird/chat": "4.20.2",
"@types/react": "^18"
"@types/react": "^19.1.1"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,19 @@ describe('useChannelMessagesReducer', () => {
const updatedMessages = [
createMockMessage({
...sentMessages[0],
reactions: [{ key: 'string', userIds: [], updatedAt: Date.now(), isEmpty: false, applyEvent: jest.fn() }],
reactions: [
{
key: 'string',
userIds: [],
updatedAt: Date.now(),
isEmpty: false,
applyEvent: jest.fn(),
sampledUserIds: [],
sampledUserInfoList: [],
count: 0,
hasCurrentUserReacted: false,
},
],
}),
];

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { act, renderHook, waitFor } from '@testing-library/react-native';
import { renderHook, waitFor } from '@testing-library/react-native';

import { ChannelType } from '@sendbird/chat';
import { SendingStatus } from '@sendbird/chat/message';
Expand Down Expand Up @@ -174,26 +174,17 @@ describe('useMessageOutgoingStatus', () => {

renderHook(() => useMessageOutgoingStatus(sdk, channel, message));

act(() => {
sdk.__emit('channel', 'group_onUndeliveredMemberStatusUpdated', channel);
});

sdk.__emit('channel', 'group_onUndeliveredMemberStatusUpdated', channel);
await waitFor(() => {
expect(forceUpdate).toHaveBeenCalledTimes(1);
});

act(() => {
sdk.__emit('channel', 'group_onUserMarkedRead', channel);
});

sdk.__emit('channel', 'group_onUserMarkedRead', channel);
await waitFor(() => {
expect(forceUpdate).toHaveBeenCalledTimes(2);
});

act(() => {
sdk.__emit('channel', 'group_onUserMarkedUnread', channel);
});

sdk.__emit('channel', 'group_onUserMarkedUnread', channel);
await waitFor(() => {
expect(forceUpdate).toHaveBeenCalledTimes(3);
});
Expand Down Expand Up @@ -226,11 +217,9 @@ describe('useMessageOutgoingStatus', () => {
const { unmount } = renderHook(() => useMessageOutgoingStatus(sdk, channel, message));
unmount();

act(() => {
sdk.__emit('channel', 'group_onUndeliveredMemberStatusUpdated', channel);
sdk.__emit('channel', 'group_onUserMarkedRead', channel);
sdk.__emit('channel', 'group_onUserMarkedUnread', channel);
});
sdk.__emit('channel', 'group_onUndeliveredMemberStatusUpdated', channel);
sdk.__emit('channel', 'group_onUserMarkedRead', channel);
sdk.__emit('channel', 'group_onUserMarkedUnread', channel);

await waitFor(() => {
expect(forceUpdate).not.toHaveBeenCalled();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export const useGroupChannelListWithCollection: UseGroupChannelList = (sdk, user
const handlerId = useUniqHandlerId('useGroupChannelListWithCollection');
const { deliveryReceiptEnabled } = useAppFeatures(sdk);

const collectionRef = useRef<SendbirdGroupChannelCollection>();
const collectionRef = useRef<SendbirdGroupChannelCollection | undefined>(undefined);

const { loading, groupChannels, refreshing, appendChannels, deleteChannels, updateRefreshing, updateLoading } =
useGroupChannelListReducer();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const createGroupChannelListQuery = (
* */
export const useGroupChannelListWithQuery: UseGroupChannelList = (sdk, userId, options) => {
const { deliveryReceiptEnabled } = useAppFeatures(sdk);
const queryRef = useRef<SendbirdGroupChannelListQuery>();
const queryRef = useRef<SendbirdGroupChannelListQuery | undefined>(undefined);
const handlerId = useUniqHandlerId('useGroupChannelListWithQuery');

const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export const useGroupChannelMessagesWithCollection: UseGroupChannelMessages = (s
const initialLimit = shouldUseSearchLimit(initialStartingPoint) ? MESSAGE_LIMIT.SEARCH : MESSAGE_LIMIT.DEFAULT;

const forceUpdate = useForceUpdate();
const collectionRef = useRef<SendbirdMessageCollection>();
const collectionRef = useRef<SendbirdMessageCollection | undefined>(undefined);
const collectionInitializedRef = useRef(false);
const handlerId = useUniqHandlerId('useGroupChannelMessagesWithCollection');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const createMessageQuery = (channel: SendbirdGroupChannel, options?: UseGroupCha
* @deprecated This hook is deprecated and will be replaced by the '@sendbird/uikit-tools' package.
* */
export const useGroupChannelMessagesWithQuery: UseGroupChannelMessages = (sdk, channel, userId, options) => {
const queryRef = useRef<SendbirdPreviousMessageListQuery>();
const queryRef = useRef<SendbirdPreviousMessageListQuery | undefined>(undefined);
const handlerId = useUniqHandlerId('useGroupChannelMessagesWithQuery');

const forceUpdate = useForceUpdate();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const createOpenChannelListQuery = (sdk: SendbirdChatSDK, queryCreator: UseOpenC
};

export const useOpenChannelListWithQuery: UseOpenChannelList = (sdk, userId, options) => {
const queryRef = useRef<SendbirdOpenChannelListQuery>();
const queryRef = useRef<SendbirdOpenChannelListQuery | undefined>(undefined);
const handlerId = useUniqHandlerId('useOpenChannelListWithQuery');

const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const createMessageQuery = (channel: SendbirdOpenChannel, creator?: UseOpenChann
};

export const useOpenChannelMessagesWithQuery: UseOpenChannelMessages = (sdk, channel, userId, options) => {
const queryRef = useRef<SendbirdPreviousMessageListQuery>();
const queryRef = useRef<SendbirdPreviousMessageListQuery | undefined>(undefined);
const forceUpdate = useForceUpdate();
const handlerId = useUniqHandlerId('useOpenChannelMessagesWithQuery');

Expand Down
2 changes: 1 addition & 1 deletion packages/uikit-chat-hooks/src/common/useUserList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export const useUserList = <
sdk: SendbirdChatSDK,
options?: UseUserListOptions<QueriedUser>,
): UseUserListReturn<QueriedUser> => {
const query = useRef<CustomQueryInterface<QueriedUser>>();
const query = useRef<CustomQueryInterface<QueriedUser> | undefined>(undefined);

const [error, setError] = useState<unknown>(null);
const [loading, setLoading] = useState(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const useConnectionHandler = (
handlerId: string,
hookHandler: Partial<ConnectionHandler>,
) => {
const handlerRef = useRef<Partial<ConnectionHandler>>();
const handlerRef = useRef<Partial<ConnectionHandler> | undefined>(undefined);
useLayoutEffect(() => {
handlerRef.current = hookHandler;
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const useRetry = (hasError: boolean, retryCount = 5) => {

const forceUpdate = useForceUpdate();
const retryCountRef = useRef(1);
const retryTimeoutRef = useRef<NodeJS.Timeout>();
const retryTimeoutRef = useRef<NodeJS.Timeout | undefined>(undefined);

useEffect(() => {
if (hasError) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import React, { ReactElement } from 'react';
import React from 'react';
import { StyleProp, View, ViewStyle } from 'react-native';

const MAX = 4;

type AvatarChildProps = {
size?: number;
square?: boolean;
containerStyle?: StyleProp<ViewStyle>;
};

type Props = React.PropsWithChildren<{
size?: number;
containerStyle?: StyleProp<ViewStyle>;
Expand Down Expand Up @@ -33,7 +39,9 @@ const AvatarGroup = ({ children, containerStyle, size = 56 }: Props) => {
if (index + 1 > MAX) return child;
if (!React.isValidElement(child)) return child;

if (childAmount === 1) return React.cloneElement(child as ReactElement, { size, containerStyle });
if (childAmount === 1) {
return React.cloneElement(child as React.ReactElement<AvatarChildProps>, { size, containerStyle });
}

const top = getTopPoint(index, childAmount) * size;
const start = getStartPoint(index) * size;
Expand All @@ -44,7 +52,7 @@ const AvatarGroup = ({ children, containerStyle, size = 56 }: Props) => {

return (
<View style={{ overflow: 'hidden', position: 'absolute', top, start, width, height }}>
{React.cloneElement(child as ReactElement, {
{React.cloneElement(child as React.ReactElement<AvatarChildProps>, {
size,
square: true,
containerStyle: { start: innerStart, top: innerTop },
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import React, { ReactElement } from 'react';
import React from 'react';
import { StyleProp, View, ViewStyle } from 'react-native';

import Text from '../../components/Text';
import useUIKitTheme from '../../theme/useUIKitTheme';

type AvatarChildProps = {
size?: number;
containerStyle?: StyleProp<ViewStyle>;
};

const DEFAULT_MAX = 3;
const DEFAULT_BORDER_WIDTH = 2;
const DEFAULT_AVATAR_GAP = -4;
Expand Down Expand Up @@ -49,7 +54,7 @@ const AvatarStack = ({

const renderAvatars = () => {
return childrenArray.slice(0, maxAvatar).map((child, index) =>
React.cloneElement(child as ReactElement, {
React.cloneElement(child as React.ReactElement<AvatarChildProps>, {
size: actualSize,
containerStyle: {
start: actualGap * index,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ type Props = React.PropsWithChildren<{
}>;
const DISMISS_TIMEOUT = 3000;
export const DialogProvider = ({ defaultLabels, children }: Props) => {
const waitDismissTimeout = useRef<NodeJS.Timeout>();
const waitDismissPromise = useRef<() => void>();
const waitDismissTimeout = useRef<NodeJS.Timeout | undefined>(undefined);
const waitDismissPromise = useRef<(() => void) | undefined>(undefined);
const waitDismiss = useCallback((resolver: () => void) => {
waitDismissPromise.current = resolver;
waitDismissTimeout.current = setTimeout(completeDismiss, DISMISS_TIMEOUT);
Expand All @@ -68,7 +68,7 @@ export const DialogProvider = ({ defaultLabels, children }: Props) => {

const render = useForceUpdate();
const dialogQueue = useRef<DialogJob[]>([]);
const workingDialogJob = useRef<DialogJob>();
const workingDialogJob = useRef<DialogJob | undefined>(undefined);
const visibleState = useRef(false);

const isProcessing = () => Boolean(workingDialogJob.current);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -526,5 +526,7 @@ const styles = createStyleSheet({
},
});

// NOTE: Due to Generic inference is not working on forwardRef, we need to cast it as typeof ChannelMessageList and implicit `ref` prop
export default React.forwardRef(ChannelMessageList) as typeof ChannelMessageList;
// NOTE: Due to Generic inference is not working on forwardRef, we need to cast it properly for React 19 compatibility
export default React.forwardRef(ChannelMessageList) as <T extends SendbirdGroupChannel | SendbirdOpenChannel>(
props: ChannelMessageListProps<T>,
) => React.ReactElement | null;
Original file line number Diff line number Diff line change
Expand Up @@ -409,5 +409,7 @@ const styles = createStyleSheet({
},
});

// NOTE: Due to Generic inference is not working on forwardRef, we need to cast it as typeof ChannelMessageList and implicit `ref` prop
export default React.forwardRef(ChannelThreadMessageList) as typeof ChannelThreadMessageList;
// NOTE: Due to Generic inference is not working on forwardRef, we need to cast it properly for React 19 compatibility
export default React.forwardRef(ChannelThreadMessageList) as <T extends SendbirdGroupChannel | SendbirdOpenChannel>(
props: ChannelThreadMessageListProps<T>,
) => React.ReactElement | null;
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ const ZoomableImageView = ({
}) => {
const { width, height } = useWindowDimensions();

const imageSize = useRef<{ width: number; height: number }>();
const imageSize = useRef<{ width: number; height: number } | undefined>(undefined);
const [contentSizeProps, setContentSizeProps] = useState<{
contentWidth: number;
contentHeight: number;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const ReactionUserListBottomSheet = ({
const { colors } = useUIKitTheme();

const [tabIndex, setTabIndex] = useState(0);
const scrollRef = useRef<ScrollView>();
const scrollRef = useRef<ScrollView | undefined>(undefined);
const tabIndicatorValue = useRef<Array<{ x: number; width: number }>>([]);
const tabIndicatorAnimated = useRef({ x: new Animated.Value(0), width: new Animated.Value(0) }).current;
const focusedWithLayoutCalculated = useRef(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const GroupChannelMessageList = (props: GroupChannelProps['MessageList']) => {
const isNewLineExistInChannelRef = useRef(false);
const scrolledAwayFromBottomRef = useRef(false);
const [isVisibleUnreadMessageFloating, setIsVisibleUnreadMessageFloating] = useState(false);
const viewableMessages = useRef<SendbirdMessage[]>();
const viewableMessages = useRef<SendbirdMessage[] | undefined>(undefined);
const hasUserMarkedAsUnreadRef = useRef(false);
const [unreadFirstMessage, setUnreadFirstMessage] = useState<SendbirdMessage | undefined>(undefined);
const pendingBottomReachedRef = useRef<{ timeout: number; timestamp: number } | null>(null);
Expand Down Expand Up @@ -216,7 +216,7 @@ const GroupChannelMessageList = (props: GroupChannelProps['MessageList']) => {
isNewLineExistInChannelRef.current = !!props.isNewLineExistInChannel && !!viewableMessages.current;
}, [props.isNewLineExistInChannel, viewableMessages.current]);

const unreadMessagesFloatingPropsRef = useRef<UnreadMessagesFloatingProps>();
const unreadMessagesFloatingPropsRef = useRef<UnreadMessagesFloatingProps | undefined>(undefined);
const updateUnreadMessagesFloatingProps = useFreshCallback(() => {
const canAutoMarkAsRead =
!scrolledAwayFromBottomRef.current &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const createGroupChannelMembersFragment = (
sortComparator,
queryCreator = () => channel.createMemberListQuery({ limit: 20 }),
}) => {
const refreshSchedule = useRef<NodeJS.Timeout>();
const refreshSchedule = useRef<NodeJS.Timeout | undefined>(undefined);
const { STRINGS } = useLocalization();
const { sdk, currentUser } = useSendbirdChat();
const { openMenu } = useActionMenu();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const createOpenChannelParticipantsFragment = (
}) => {
const handlerId = useUniqHandlerId('OpenChannelParticipantsFragment');

const refreshSchedule = useRef<NodeJS.Timeout>();
const refreshSchedule = useRef<NodeJS.Timeout | undefined>(undefined);
const { STRINGS } = useLocalization();
const { sdk, currentUser } = useSendbirdChat();
const { openMenu } = useActionMenu();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const useMentionTextInput = (params: { messageToEdit?: SendbirdUserMessage | Sen
const { mentionManager, sbOptions } = useSendbirdChat();

const mentionedUsersRef = useRef<MentionedUser[]>([]);
const textInputRef = useRef<TextInput>();
const textInputRef = useRef<TextInput | undefined>(undefined);

const [text, setText] = useState('');
const [selection, setSelection] = useState({ start: 0, end: 0 });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const usePushTokenRegistration = () => {
const { sdk } = useSendbirdChat();
const { notificationService } = usePlatformService();

const refreshListener = useRef<() => void>();
const refreshListener = useRef<(() => void) | undefined>(undefined);
const [registerToken, unregisterToken, getToken] = useIIFE(() => {
return [
Platform.select({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ const useVoiceMessageInput = ({ onSend, onClose }: Props): VoiceMessageInputResu
duration: 0,
});

const recordingPath = useRef<{ recordFilePath: string; uri: string }>();
const recordingPath = useRef<{ recordFilePath: string; uri: string } | undefined>(undefined);
const getVoiceMessageRecordingPath = () => {
if (!recordingPath.current) throw new Error('No recording path');
return recordingPath.current;
Expand Down
Loading