Changeset View
Changeset View
Standalone View
Standalone View
web/chat/chat-message-list-container.react.js
// @flow | // @flow | ||||
import classNames from 'classnames'; | import classNames from 'classnames'; | ||||
import invariant from 'invariant'; | import invariant from 'invariant'; | ||||
import _isEqual from 'lodash/fp/isEqual.js'; | import _isEqual from 'lodash/fp/isEqual.js'; | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { useDrop } from 'react-dnd'; | import { useDrop } from 'react-dnd'; | ||||
import { NativeTypes } from 'react-dnd-html5-backend'; | import { NativeTypes } from 'react-dnd-html5-backend'; | ||||
import { useDispatch } from 'react-redux'; | import { useDispatch } from 'react-redux'; | ||||
import { useLoggedInUserInfo } from 'lib/hooks/account-hooks.js'; | import { useWatchThread, threadIsPending } from 'lib/shared/thread-utils.js'; | ||||
import { threadInfoSelector } from 'lib/selectors/thread-selectors.js'; | |||||
import { userInfoSelectorForPotentialMembers } from 'lib/selectors/user-selectors.js'; | |||||
import { | |||||
useWatchThread, | |||||
useExistingThreadInfoFinder, | |||||
createPendingThread, | |||||
threadIsPending, | |||||
} from 'lib/shared/thread-utils.js'; | |||||
import { threadTypes } from 'lib/types/thread-types.js'; | |||||
import type { AccountUserInfo } from 'lib/types/user-types.js'; | |||||
import ChatInputBar from './chat-input-bar.react.js'; | import ChatInputBar from './chat-input-bar.react.js'; | ||||
import css from './chat-message-list-container.css'; | import css from './chat-message-list-container.css'; | ||||
import ChatMessageList from './chat-message-list.react.js'; | import ChatMessageList from './chat-message-list.react.js'; | ||||
import ChatThreadComposer from './chat-thread-composer.react.js'; | import ChatThreadComposer from './chat-thread-composer.react.js'; | ||||
import ThreadTopBar from './thread-top-bar.react.js'; | import ThreadTopBar from './thread-top-bar.react.js'; | ||||
import { InputStateContext } from '../input/input-state.js'; | import { InputStateContext } from '../input/input-state.js'; | ||||
import { updateNavInfoActionType } from '../redux/action-types.js'; | import { updateNavInfoActionType } from '../redux/action-types.js'; | ||||
import { useSelector } from '../redux/redux-utils.js'; | import { | ||||
useThreadInfoForPossiblyPendingThread, | |||||
useInfosForPendingThread, | |||||
} from '../utils/thread-utils.js'; | |||||
type Props = { | type Props = { | ||||
+activeChatThreadID: string, | +activeChatThreadID: string, | ||||
}; | }; | ||||
function ChatMessageListContainer(props: Props): React.Node { | function ChatMessageListContainer(props: Props): React.Node { | ||||
const { activeChatThreadID } = props; | const { activeChatThreadID } = props; | ||||
const isChatCreation = | const { | ||||
useSelector(state => state.navInfo.chatMode) === 'create'; | |||||
const selectedUserIDs = useSelector(state => state.navInfo.selectedUserList); | |||||
const otherUserInfos = useSelector(userInfoSelectorForPotentialMembers); | |||||
const userInfoInputArray: $ReadOnlyArray<AccountUserInfo> = React.useMemo( | |||||
() => selectedUserIDs?.map(id => otherUserInfos[id]).filter(Boolean) ?? [], | |||||
[otherUserInfos, selectedUserIDs], | |||||
); | |||||
const loggedInUserInfo = useLoggedInUserInfo(); | |||||
invariant(loggedInUserInfo, 'loggedInUserInfo should be set'); | |||||
const pendingPrivateThread = React.useRef( | |||||
createPendingThread({ | |||||
viewerID: loggedInUserInfo.id, | |||||
threadType: threadTypes.PRIVATE, | |||||
members: [loggedInUserInfo], | |||||
}), | |||||
); | |||||
const newThreadID = 'pending/new_thread'; | |||||
const pendingNewThread = React.useMemo( | |||||
() => ({ | |||||
...createPendingThread({ | |||||
viewerID: loggedInUserInfo.id, | |||||
threadType: threadTypes.PRIVATE, | |||||
members: [loggedInUserInfo], | |||||
name: 'New thread', | |||||
}), | |||||
id: newThreadID, | |||||
}), | |||||
[loggedInUserInfo], | |||||
); | |||||
const existingThreadInfoFinderForCreatingThread = useExistingThreadInfoFinder( | |||||
pendingPrivateThread.current, | |||||
); | |||||
const baseThreadInfo = useSelector(state => { | |||||
if (!activeChatThreadID) { | |||||
return null; | |||||
} | |||||
return ( | |||||
threadInfoSelector(state)[activeChatThreadID] ?? | |||||
state.navInfo.pendingThread | |||||
); | |||||
}); | |||||
const existingThreadInfoFinder = useExistingThreadInfoFinder(baseThreadInfo); | |||||
const threadInfo = React.useMemo(() => { | |||||
if (isChatCreation) { | |||||
if (userInfoInputArray.length === 0) { | |||||
return pendingNewThread; | |||||
} | |||||
return existingThreadInfoFinderForCreatingThread({ | |||||
searching: true, | |||||
userInfoInputArray, | |||||
}); | |||||
} | |||||
return existingThreadInfoFinder({ | |||||
searching: false, | |||||
userInfoInputArray: [], | |||||
}); | |||||
}, [ | |||||
existingThreadInfoFinder, | |||||
existingThreadInfoFinderForCreatingThread, | |||||
isChatCreation, | isChatCreation, | ||||
selectedUserIDs, | |||||
otherUserInfos, | |||||
userInfoInputArray, | userInfoInputArray, | ||||
pendingNewThread, | } = useInfosForPendingThread(); | ||||
]); | |||||
const threadInfo = useThreadInfoForPossiblyPendingThread(activeChatThreadID); | |||||
invariant(threadInfo, 'ThreadInfo should be set'); | invariant(threadInfo, 'ThreadInfo should be set'); | ||||
const dispatch = useDispatch(); | const dispatch = useDispatch(); | ||||
// The effect removes members from list in navInfo | // The effect removes members from list in navInfo | ||||
// if some of the user IDs don't exist in redux store | // if some of the user IDs don't exist in redux store | ||||
React.useEffect(() => { | React.useEffect(() => { | ||||
if (!isChatCreation) { | if (!isChatCreation) { | ||||
▲ Show 20 Lines • Show All 147 Lines • Show Last 20 Lines |