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
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@ import { act, renderHook, waitFor } from '@testing-library/react-native';
import { Provider } from 'react-redux';
import { type ReactNode } from 'react';

import { ROOM } from '../../../../actions/actionsTypes';
import { type IRoomHistoryRequest } from '../../../../actions/room';
import { type RoomType, type TAnyMessageModel } from '../../../../definitions';
import database from '../../../../lib/database';
import { getMessageById } from '../../../../lib/database/services/Message';
import { getThreadById } from '../../../../lib/database/services/Thread';
import { MessageTypeLoad } from '../../../../lib/constants/messageTypeLoad';
import { readThreads } from '../../../../lib/services/restApi';
import { mockedStore } from '../../../../reducers/mockedStore';
import { MAX_AUTO_LOADS, QUERY_SIZE } from '../constants';
import { buildVisibleSystemTypesClause } from '../visibleSystemMessages';
import { useMessages } from './useMessages';

jest.mock('../../../../lib/database', () => ({
import { ROOM } from '../../../../../actions/actionsTypes';
import { type IRoomHistoryRequest } from '../../../../../actions/room';
import { type RoomType, type TAnyMessageModel } from '../../../../../definitions';
import database from '../../../../../lib/database';
import { getMessageById } from '../../../../../lib/database/services/Message';
import { getThreadById } from '../../../../../lib/database/services/Thread';
import { MessageTypeLoad } from '../../../../../lib/constants/messageTypeLoad';
import { readThreads } from '../../../../../lib/services/restApi';
import { mockedStore } from '../../../../../reducers/mockedStore';
import { MAX_AUTO_LOADS, QUERY_SIZE } from '../../constants';
import { buildVisibleSystemTypesClause } from '../../visibleSystemMessages';
import { useMessages } from '../useMessages';

jest.mock('../../../../../lib/database', () => ({
__esModule: true,
default: {
active: {
Expand All @@ -24,20 +24,20 @@ jest.mock('../../../../lib/database', () => ({
}
}));

jest.mock('../../../../lib/database/services/Message', () => ({
jest.mock('../../../../../lib/database/services/Message', () => ({
getMessageById: jest.fn(() => Promise.resolve(null))
}));

jest.mock('../../../../lib/database/services/Thread', () => ({
jest.mock('../../../../../lib/database/services/Thread', () => ({
getThreadById: jest.fn(() => Promise.resolve(null))
}));

jest.mock('../../../../lib/services/restApi', () => ({
jest.mock('../../../../../lib/services/restApi', () => ({
readThreads: jest.fn(() => Promise.resolve())
}));

jest.mock('../../../../lib/methods/helpers', () => {
const actual = jest.requireActual('../../../../lib/methods/helpers');
jest.mock('../../../../../lib/methods/helpers', () => {
const actual = jest.requireActual('../../../../../lib/methods/helpers');
return {
...actual,
useDebounce: (fn: (...args: unknown[]) => unknown) => Object.assign(fn, { cancel: jest.fn() })
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { act, renderHook, waitFor } from '@testing-library/react-native';

import { type TAnyMessageModel } from '../../../../definitions';
import { type TListRef, type TMessagesIdsRef } from '../../definitions';
import { useScroll } from './useScroll';
import { type TAnyMessageModel } from '../../../../../definitions';
import { type TListRef, type TMessagesIdsRef } from '../../../definitions';
import { useScroll } from '../useScroll';

type Row = { id: string };

Expand Down
9 changes: 6 additions & 3 deletions app/views/RoomView/hooks/useCanPlaceLivechatOnHold.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { useShallow } from 'zustand/react/shallow';

import { useSetting } from '../../../lib/hooks/useSetting';
import { useRoomStoreByRid } from '../stores/RoomStore';

export function useCanPlaceLivechatOnHold(rid?: string): boolean {
const livechatAllowManualOnHold = useSetting('Livechat_allow_manual_on_hold') as boolean;
const t = useRoomStoreByRid(rid, s => s.room.t);
const lastMessageFromAgent = useRoomStoreByRid(rid, s => s.lastMessageFromAgent);
const onHold = useRoomStoreByRid(rid, s => s.roomUpdate.onHold);
const { t, lastMessageFromAgent, onHold } = useRoomStoreByRid(
rid,
useShallow(s => ({ t: s.room.t, lastMessageFromAgent: s.lastMessageFromAgent, onHold: s.roomUpdate.onHold }))
);
return t === 'l' && !!livechatAllowManualOnHold && lastMessageFromAgent && !onHold;
}
17 changes: 11 additions & 6 deletions app/views/RoomView/hooks/useGoRoomActionsView.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { type NavigatorScreenParams, useNavigation } from '@react-navigation/native';
import { useShallow } from 'zustand/react/shallow';

import { events, logEvent } from '../../../lib/methods/helpers/log';
import { useMasterDetail } from '../../../lib/hooks/useMasterDetail';
Expand All @@ -13,13 +14,17 @@ import { useCanPlaceLivechatOnHold } from './useCanPlaceLivechatOnHold';
export const useGoRoomActionsView = (rid?: string): ((screen?: keyof ModalStackParamList) => void) => {
const navigation = useNavigation<IRoomViewProps['navigation']>();
const isMasterDetail = useMasterDetail();
// `t` comes from the store (seeded at mount) rather than route.params, which navigation can wipe.
const room = useRoomStoreByRid(rid, s => s.room);
const { room, member, joined, canForwardGuest, canViewCannedResponse } = useRoomStoreByRid(
rid,
useShallow(s => ({
room: s.room,
member: s.member,
joined: s.joined,
canForwardGuest: s.canForwardGuest,
canViewCannedResponse: s.canViewCannedResponse
}))
);
const t = room.t;
const member = useRoomStoreByRid(rid, s => s.member);
const joined = useRoomStoreByRid(rid, s => s.joined);
const canForwardGuest = useRoomStoreByRid(rid, s => s.canForwardGuest);
const canViewCannedResponse = useRoomStoreByRid(rid, s => s.canViewCannedResponse);
const canReturnQueue = useCanReturnQueue(t === 'l');
const canPlaceLivechatOnHold = useCanPlaceLivechatOnHold(rid);

Expand Down
22 changes: 21 additions & 1 deletion app/views/RoomView/hooks/useHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,26 @@ export const useHeader = ({ rid, tmid, name: roomName }: IUseHeaderParams): void
}

const headerProps = getRoomHeaderProps({ room, tmid, roomName, roomUserId, onPress: goRoomActionsView });
navigation.setOptions({ headerTitle: () => <RoomHeader {...headerProps} /> });
navigation.setOptions({
headerTitle: () => (
<RoomHeader
prid={headerProps.prid}
tmid={headerProps.tmid}
title={headerProps.title}
teamMain={headerProps.teamMain}
parentTitle={headerProps.parentTitle}
subtitle={headerProps.subtitle}
type={headerProps.type}
roomUserId={headerProps.roomUserId}
visitor={headerProps.visitor}
isGroupChat={headerProps.isGroupChat}
onPress={headerProps.onPress}
testID={headerProps.testID}
sourceType={headerProps.sourceType}
abacAttributes={headerProps.abacAttributes}
disabled={headerProps.disabled}
/>
)
});
}, [rid, tmid, roomName, room, roomUpdate, roomUserId, navigation, goRoomActionsView]);
};
5 changes: 2 additions & 3 deletions app/views/RoomView/hooks/useJumpToMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ export function useJumpToMessage({

// Live-mirrored (see useLiveRef) so the mount effect can key on [tmid] despite these being unstable.
const consumeJumpParamRef = useLiveRef(consumeJumpParam);
const onJumpParamChangedRef = useLiveRef(onJumpParamChanged);
const navToThreadRef = useLiveRef(navToThread);

useEffect(() => {
Expand All @@ -114,8 +113,8 @@ export function useJumpToMessage({
return () => task.cancel();
}, [navToThreadRef]);

useChangedParam(route.params?.jumpToMessageId, id => onJumpParamChangedRef.current(id));
useChangedParam(route.params?.jumpToThreadId, id => navToThreadRef.current({ tmid: id }));
useChangedParam(route.params?.jumpToMessageId, onJumpParamChanged);
useChangedParam(route.params?.jumpToThreadId, id => navToThread({ tmid: id }));

return { jumpToMessage, cancelJumpToMessage, onThreadMessagesLoaded };
}
2 changes: 1 addition & 1 deletion app/views/RoomView/hooks/useRoomMessageHandlers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ export function useRoomMessageHandlers({
const isMasterDetail = useMasterDetail();
const { showActionSheet } = useActionSheet();

const rid = useRoomStore(s => s.room.rid);
const room = useRoomStore(s => s.room);
const rid = room.rid;

const onDiscussionPress = async (drid: TAnyMessageModel['drid']) => {
if (!drid) return;
Expand Down
2 changes: 1 addition & 1 deletion app/views/RoomView/hooks/useRoomNavigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export function useRoomNavigation({

useEffect(() => {
cancelJumpToMessageRef.current = cancelJumpToMessage;
});
}, [cancelJumpToMessage]);

const onThreadPress = useDebounce((item: TAnyMessageModel) => navToThread(item), 1000, { leading: true, trailing: false });

Expand Down
43 changes: 20 additions & 23 deletions app/views/RoomView/hooks/useUnreadsCount.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,29 @@
import { useEffect, useState } from 'react';
import { useMemo } from 'react';
import { Q } from '@nozbe/watermelondb';

import database from '../../../lib/database';
import { isIOS } from '../../../lib/methods/helpers';
import { useObservable } from '../../../lib/hooks/useObservable';
import { type TSubscriptionModel } from '../../../definitions';

export function useUnreadsCount(rid?: string): number | null {
const [unreadsCount, setUnreadsCount] = useState<number | null>(null);
const observable = useMemo(
() =>
isIOS && rid
? database.active
.get<TSubscriptionModel>('subscriptions')
.query(Q.where('archived', false), Q.where('open', true), Q.where('rid', Q.notEq(rid)))
.observeWithColumns(['unread'])
: undefined,
[rid]
);
const rooms = useObservable(observable);

useEffect(() => {
if (!isIOS || !rid) {
return;
}
const observable = database.active
.get('subscriptions')
.query(Q.where('archived', false), Q.where('open', true), Q.where('rid', Q.notEq(rid)))
.observeWithColumns(['unread']);

const subscription = observable.subscribe((rooms: TSubscriptionModel[]) => {
const nextUnreadsCount = rooms.reduce(
(unreadCount, item) => (item.unread > 0 && !item.hideUnreadStatus ? unreadCount + item.unread : unreadCount),
0
);
setUnreadsCount(nextUnreadsCount);
});

return () => subscription.unsubscribe();
}, [rid]);

return unreadsCount;
if (!rooms) {
return null;
}
return rooms.reduce(
(unreadCount, item) => (item.unread > 0 && !item.hideUnreadStatus ? unreadCount + item.unread : unreadCount),
0
);
}
Loading