import React from 'react'; import { AutoSizer, List } from 'react-virtualized'; import { ConversationListItem, PropsData as ConversationListItemPropsType, } from './ConversationListItem'; import { PropsData as SearchResultsProps, SearchResults, } from './SearchResults'; import { LocalizerType } from '../types/Util'; export interface Props { conversations?: Array; archivedConversations?: Array; searchResults?: SearchResultsProps; showArchived?: boolean; i18n: LocalizerType; // Action Creators startNewConversation: ( query: string, options: { regionCode: string } ) => void; openConversationInternal: (id: string, messageId?: string) => void; showArchivedConversations: () => void; showInbox: () => void; // Render Props renderMainHeader: () => JSX.Element; } // from https://github.com/bvaughn/react-virtualized/blob/fb3484ed5dcc41bffae8eab029126c0fb8f7abc0/source/List/types.js#L5 type RowRendererParamsType = { index: number; isScrolling: boolean; isVisible: boolean; key: string; parent: Object; style: Object; }; export class LeftPane extends React.Component { public listRef: React.RefObject = React.createRef(); public scrollToTop() { if (this.listRef && this.listRef.current) { const { current } = this.listRef; current.scrollToRow(0); } } public componentDidUpdate(prevProps: Props) { const { showArchived, searchResults } = this.props; const isNotShowingSearchResults = !searchResults; const hasArchiveViewChanged = showArchived !== prevProps.showArchived; if (isNotShowingSearchResults && hasArchiveViewChanged) { this.scrollToTop(); } } public renderRow = ({ index, key, style, }: RowRendererParamsType): JSX.Element => { const { archivedConversations, conversations, i18n, openConversationInternal, showArchived, } = this.props; if (!conversations || !archivedConversations) { throw new Error( 'renderRow: Tried to render without conversations or archivedConversations' ); } if (!showArchived && index === conversations.length) { return this.renderArchivedButton({ key, style }); } const conversation = showArchived ? archivedConversations[index] : conversations[index]; return ( ); }; public renderArchivedButton({ key, style, }: { key: string; style: Object; }): JSX.Element { const { archivedConversations, i18n, showArchivedConversations, } = this.props; if (!archivedConversations || !archivedConversations.length) { throw new Error( 'renderArchivedButton: Tried to render without archivedConversations' ); } return (
{i18n('archivedConversations')}{' '} {archivedConversations.length}
); } public renderList(): JSX.Element { const { archivedConversations, i18n, conversations, openConversationInternal, startNewConversation, searchResults, showArchived, } = this.props; if (searchResults) { return ( ); } if (!conversations || !archivedConversations) { throw new Error( 'render: must provided conversations and archivedConverstions if no search results are provided' ); } // That extra 1 element added to the list is the 'archived converastions' button const length = showArchived ? archivedConversations.length : conversations.length + (archivedConversations.length ? 1 : 0); // Note: conversations is not a known prop for List, but it is required to ensure that // it re-renders when our conversation data changes. Otherwise it would just render // on startup and scroll. return (
{showArchived ? (
{i18n('archiveHelperText')}
) : null} {({ height, width }) => ( )}
); } public renderArchivedHeader(): JSX.Element { const { i18n, showInbox } = this.props; return (
{i18n('archivedConversations')}
); } public render(): JSX.Element { const { renderMainHeader, showArchived } = this.props; return (
{showArchived ? this.renderArchivedHeader() : renderMainHeader()}
{this.renderList()}
); } }