Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F32084389
D4434.1765005714.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
12 KB
Referenced Files
None
Subscribers
None
D4434.1765005714.diff
View Options
diff --git a/web/chat/chat-message-list-container.css b/web/chat/chat-message-list-container.css
new file mode 100644
--- /dev/null
+++ b/web/chat/chat-message-list-container.css
@@ -0,0 +1,12 @@
+div.container {
+ margin-left: 400px;
+ height: 100%;
+ background-color: var(--bg);
+ display: flex;
+ flex-direction: column;
+ box-sizing: border-box;
+}
+div.activeContainer {
+ border: 2px solid #5989d6;
+ margin-left: 402px;
+}
diff --git a/web/chat/chat-message-list-container.react.js b/web/chat/chat-message-list-container.react.js
new file mode 100644
--- /dev/null
+++ b/web/chat/chat-message-list-container.react.js
@@ -0,0 +1,109 @@
+// @flow
+
+import classNames from 'classnames';
+import invariant from 'invariant';
+import * as React from 'react';
+import { useDrop } from 'react-dnd';
+import { NativeTypes } from 'react-dnd-html5-backend';
+
+import { threadInfoSelector } from 'lib/selectors/thread-selectors';
+import {
+ useWatchThread,
+ useExistingThreadInfoFinder,
+} from 'lib/shared/thread-utils';
+
+import { InputStateContext } from '../input/input-state';
+import { useSelector } from '../redux/redux-utils';
+import ChatInputBar from './chat-input-bar.react';
+import css from './chat-message-list-container.css';
+import ChatMessageList from './chat-message-list.react';
+import ThreadTopBar from './thread-top-bar.react';
+
+function ChatMessageListContainer(): React.Node {
+ const activeChatThreadID = useSelector(
+ state => state.navInfo.activeChatThreadID,
+ );
+ const baseThreadInfo = useSelector(state => {
+ if (!activeChatThreadID) {
+ return null;
+ }
+ return (
+ threadInfoSelector(state)[activeChatThreadID] ??
+ state.navInfo.pendingThread
+ );
+ });
+ const existingThreadInfoFinder = useExistingThreadInfoFinder(baseThreadInfo);
+ const threadInfo = React.useMemo(
+ () =>
+ existingThreadInfoFinder({
+ searching: false,
+ userInfoInputArray: [],
+ }),
+ [existingThreadInfoFinder],
+ );
+ invariant(threadInfo, 'ThreadInfo should be set');
+
+ const inputState = React.useContext(InputStateContext);
+ invariant(inputState, 'InputState should be set');
+ const [{ isActive }, connectDropTarget] = useDrop({
+ accept: NativeTypes.FILE,
+ drop: item => {
+ const { files } = item;
+ if (inputState && files.length > 0) {
+ inputState.appendFiles(files);
+ }
+ },
+ collect: monitor => ({
+ isActive: monitor.isOver() && monitor.canDrop(),
+ }),
+ });
+
+ useWatchThread(threadInfo);
+
+ const containerStyle = classNames({
+ [css.container]: true,
+ [css.activeContainer]: isActive,
+ });
+
+ const containerRef = React.useRef();
+
+ const onPaste = React.useCallback(
+ (e: ClipboardEvent) => {
+ if (!inputState) {
+ return;
+ }
+ const { clipboardData } = e;
+ if (!clipboardData) {
+ return;
+ }
+ const { files } = clipboardData;
+ if (files.length === 0) {
+ return;
+ }
+ e.preventDefault();
+ inputState.appendFiles([...files]);
+ },
+ [inputState],
+ );
+
+ React.useEffect(() => {
+ const currentContainerRef = containerRef.current;
+ if (!currentContainerRef) {
+ return;
+ }
+ currentContainerRef.addEventListener('paste', onPaste);
+ return () => {
+ currentContainerRef.removeEventListener('paste', onPaste);
+ };
+ }, [onPaste]);
+
+ return connectDropTarget(
+ <div className={containerStyle} ref={containerRef}>
+ <ThreadTopBar threadInfo={threadInfo} />
+ <ChatMessageList threadInfo={threadInfo} />
+ <ChatInputBar threadInfo={threadInfo} inputState={inputState} />
+ </div>,
+ );
+}
+
+export default ChatMessageListContainer;
diff --git a/web/chat/chat-message-list.css b/web/chat/chat-message-list.css
--- a/web/chat/chat-message-list.css
+++ b/web/chat/chat-message-list.css
@@ -1,15 +1,3 @@
-div.container {
- margin-left: 400px;
- height: 100%;
- background-color: var(--bg);
- display: flex;
- flex-direction: column;
- box-sizing: border-box;
-}
-div.activeContainer {
- border: 2px solid #5989d6;
- margin-left: 402px;
-}
div.outerMessageContainer {
position: relative;
height: calc(100vh - 128px);
diff --git a/web/chat/chat-message-list.react.js b/web/chat/chat-message-list.react.js
--- a/web/chat/chat-message-list.react.js
+++ b/web/chat/chat-message-list.react.js
@@ -4,8 +4,6 @@
import { detect as detectBrowser } from 'detect-browser';
import invariant from 'invariant';
import * as React from 'react';
-import { useDrop } from 'react-dnd';
-import { NativeTypes } from 'react-dnd-html5-backend';
import {
fetchMessagesBeforeCursorActionTypes,
@@ -18,13 +16,8 @@
type ChatMessageItem,
useMessageListData,
} from 'lib/selectors/chat-selectors';
-import { threadInfoSelector } from 'lib/selectors/thread-selectors';
import { messageKey } from 'lib/shared/message-utils';
-import {
- useWatchThread,
- useExistingThreadInfoFinder,
- threadIsPending,
-} from 'lib/shared/thread-utils';
+import { threadIsPending } from 'lib/shared/thread-utils';
import type { FetchMessageInfosPayload } from 'lib/types/message-types';
import { type ThreadInfo } from 'lib/types/thread-types';
import {
@@ -37,7 +30,6 @@
import LoadingIndicator from '../loading-indicator.react';
import { useTextMessageRulesFunc } from '../markdown/rules.react';
import { useSelector } from '../redux/redux-utils';
-import ChatInputBar from './chat-input-bar.react';
import css from './chat-message-list.css';
import { MessageListContext } from './message-list-types';
import Message from './message.react';
@@ -46,12 +38,15 @@
MessagePositionInfo,
} from './position-types';
import RelationshipPrompt from './relationship-prompt/relationship-prompt';
-import ThreadTopBar from './thread-top-bar.react';
-type PassedProps = {
+type BaseProps = {
+ +threadInfo: ThreadInfo,
+};
+
+type Props = {
+ ...BaseProps,
// Redux state
+activeChatThreadID: ?string,
- +threadInfo: ?ThreadInfo,
+messageListData: ?$ReadOnlyArray<ChatMessageItem>,
+startReached: boolean,
+timeZone: ?string,
@@ -69,14 +64,6 @@
// withInputState
+inputState: ?InputState,
};
-type ReactDnDProps = {
- +isActive: boolean,
- +connectDropTarget: (node: React.Node) => React.Node,
-};
-type Props = {
- ...PassedProps,
- ...ReactDnDProps,
-};
type State = {
+mouseOverMessagePosition: ?OnMessagePositionWithContainerInfo,
};
@@ -243,73 +230,32 @@
};
render() {
- const {
- messageListData,
- threadInfo,
- inputState,
- connectDropTarget,
- isActive,
- } = this.props;
+ const { messageListData, threadInfo, inputState } = this.props;
if (!messageListData) {
return <div className={css.container} />;
}
- invariant(threadInfo, 'ThreadInfo should be set if messageListData is');
invariant(inputState, 'InputState should be set');
const messages = messageListData.map(this.renderItem);
- const containerStyle = classNames({
- [css.container]: true,
- [css.activeContainer]: isActive,
- });
let relationshipPrompt;
- if (this.props.threadInfo) {
- relationshipPrompt = (
- <RelationshipPrompt threadInfo={this.props.threadInfo} />
- );
+ if (threadInfo) {
+ relationshipPrompt = <RelationshipPrompt threadInfo={threadInfo} />;
}
const messageContainerStyle = classNames({
[css.messageContainer]: true,
[css.mirroredMessageContainer]: !this.props.supportsReverseFlex,
});
- return connectDropTarget(
- <div className={containerStyle} ref={this.containerRef}>
- <ThreadTopBar threadInfo={threadInfo} />
- <div className={css.outerMessageContainer}>
- {relationshipPrompt}
- <div className={messageContainerStyle} ref={this.messageContainerRef}>
- {messages}
- </div>
+ return (
+ <div className={css.outerMessageContainer}>
+ {relationshipPrompt}
+ <div className={messageContainerStyle} ref={this.messageContainerRef}>
+ {messages}
</div>
- <ChatInputBar threadInfo={threadInfo} inputState={inputState} />
- </div>,
+ </div>
);
}
- containerRef = (container: ?HTMLDivElement) => {
- if (container) {
- container.addEventListener('paste', this.onPaste);
- }
- this.container = container;
- };
-
- onPaste = (e: ClipboardEvent) => {
- const { inputState } = this.props;
- if (!inputState) {
- return;
- }
- const { clipboardData } = e;
- if (!clipboardData) {
- return;
- }
- const { files } = clipboardData;
- if (files.length === 0) {
- return;
- }
- e.preventDefault();
- inputState.appendFiles([...files]);
- };
-
messageContainerRef = (messageContainer: ?HTMLDivElement) => {
this.messageContainer = messageContainer;
// In case we already have all the most recent messages,
@@ -379,8 +325,9 @@
registerFetchKey(fetchMessagesBeforeCursorActionTypes);
registerFetchKey(fetchMostRecentMessagesActionTypes);
-const ConnectedChatMessageList: React.ComponentType<{}> = React.memo<{}>(
- function ConnectedChatMessageList(): React.Node {
+const ConnectedChatMessageList: React.ComponentType<BaseProps> = React.memo<BaseProps>(
+ function ConnectedChatMessageList(props: BaseProps): React.Node {
+ const { threadInfo } = props;
const userAgent = useSelector(state => state.userAgent);
const supportsReverseFlex = React.useMemo(() => {
const browser = detectBrowser(userAgent);
@@ -393,41 +340,19 @@
const timeZone = useSelector(state => state.timeZone);
- const activeChatThreadID = useSelector(
- state => state.navInfo.activeChatThreadID,
- );
- const baseThreadInfo = useSelector(state => {
- const activeID = state.navInfo.activeChatThreadID;
- if (!activeID) {
- return null;
- }
- return threadInfoSelector(state)[activeID] ?? state.navInfo.pendingThread;
- });
- const existingThreadInfoFinder = useExistingThreadInfoFinder(
- baseThreadInfo,
- );
- const threadInfo = React.useMemo(
- () =>
- existingThreadInfoFinder({
- searching: false,
- userInfoInputArray: [],
- }),
- [existingThreadInfoFinder],
- );
-
const messageListData = useMessageListData({
threadInfo,
searching: false,
userInfoInputArray: [],
});
- const startReached = useSelector(state => {
- const activeID = state.navInfo.activeChatThreadID;
+ const startReached = !!useSelector(state => {
+ const activeID = threadInfo.id;
if (!activeID) {
return null;
}
- if (threadIsPending(threadInfo?.id)) {
+ if (threadIsPending(activeID)) {
return true;
}
@@ -445,20 +370,8 @@
const callFetchMostRecentMessages = useServerCall(fetchMostRecentMessages);
const inputState = React.useContext(InputStateContext);
- const [dndProps, connectDropTarget] = useDrop({
- accept: NativeTypes.FILE,
- drop: item => {
- const { files } = item;
- if (inputState && files.length > 0) {
- inputState.appendFiles(files);
- }
- },
- collect: monitor => ({
- isActive: monitor.isOver() && monitor.canDrop(),
- }),
- });
- const getTextMessageMarkdownRules = useTextMessageRulesFunc(threadInfo?.id);
+ const getTextMessageMarkdownRules = useTextMessageRulesFunc(threadInfo.id);
const messageListContext = React.useMemo(() => {
if (!getTextMessageMarkdownRules) {
return undefined;
@@ -466,12 +379,10 @@
return { getTextMessageMarkdownRules };
}, [getTextMessageMarkdownRules]);
- useWatchThread(threadInfo);
-
return (
<MessageListContext.Provider value={messageListContext}>
<ChatMessageList
- activeChatThreadID={activeChatThreadID}
+ activeChatThreadID={threadInfo.id}
threadInfo={threadInfo}
messageListData={messageListData}
startReached={startReached}
@@ -481,8 +392,6 @@
dispatchActionPromise={dispatchActionPromise}
fetchMessagesBeforeCursor={callFetchMessagesBeforeCursor}
fetchMostRecentMessages={callFetchMostRecentMessages}
- {...dndProps}
- connectDropTarget={connectDropTarget}
/>
</MessageListContext.Provider>
);
diff --git a/web/chat/chat.react.js b/web/chat/chat.react.js
--- a/web/chat/chat.react.js
+++ b/web/chat/chat.react.js
@@ -2,7 +2,7 @@
import * as React from 'react';
-import ChatMessageList from './chat-message-list.react';
+import ChatMessageListContainer from './chat-message-list-container.react';
import ChatTabs from './chat-tabs.react';
import { ThreadListProvider } from './thread-list-provider';
@@ -12,7 +12,7 @@
<ThreadListProvider>
<ChatTabs />
</ThreadListProvider>
- <ChatMessageList />
+ <ChatMessageListContainer />
</>
);
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Dec 6, 7:21 AM (3 h, 1 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5833696
Default Alt Text
D4434.1765005714.diff (12 KB)
Attached To
Mode
D4434: [web] Separate `ChatMessageListContainer` from `ChatMessageList`
Attached
Detach File
Event Timeline
Log In to Comment