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 { SessionButton } from './SessionButton'; import { SessionConversationSearch } from './SessionConversationSearch'; import { debounce } from 'lodash'; import { cleanSearchTerm } from '../../util/cleanSearchTerm'; import { SearchOptions } from '../../types/Search'; import { SessionIconButton, SessionIconSize, SessionIconType } from './icon'; import { SessionIdEditable } from './SessionIdEditable'; export interface Props { searchTerm: string; isSecondaryDevice: boolean; conversations?: Array; friends?: Array; searchResults?: SearchResultsProps; // Action Creators startNewConversation: ( query: string, options: { regionCode: string } ) => void; updateSearchTerm: (searchTerm: string) => void; search: (query: string, options: SearchOptions) => void; openConversationInternal: (id: string, messageId?: string) => void; clearSearch: () => void; } // 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 LeftPaneMessageSection extends React.Component { private readonly updateSearchBound: (searchedString: string) => void; private readonly debouncedSearch: (searchTerm: string) => void; public constructor(props: Props) { super(props); this.state = { showComposeView: false, }; this.updateSearchBound = this.updateSearch.bind(this); this.handleComposeClick = this.handleComposeClick.bind(this); this.handleOnPasteSessionID = this.handleOnPasteSessionID.bind(this); this.debouncedSearch = debounce(this.search.bind(this), 20); } public getCurrentConversations(): | Array | undefined { const { conversations } = this.props; let conversationList = conversations; if (conversationList !== undefined) { conversationList = conversationList.filter( conversation => !conversation.isSecondary ); } return conversationList; } public renderRow = ({ index, key, style, }: RowRendererParamsType): JSX.Element => { const { openConversationInternal } = this.props; const conversations = this.getCurrentConversations(); if (!conversations) { throw new Error('renderRow: Tried to render without conversations'); } const conversation = conversations[index]; return ( ); }; public renderList(): JSX.Element | Array { const { openConversationInternal, startNewConversation, searchResults, } = this.props; if (searchResults) { return ( ); } const conversations = this.getCurrentConversations(); if (!conversations) { throw new Error( 'render: must provided conversations if no search results are provided' ); } // That extra 1 element added to the list is the 'archived conversations' button const length = conversations.length; // We ensure that the listKey differs between inbox and archive views, which ensures // that AutoSizer properly detects the new size of its slot in the flexbox. The // archive explainer text at the top of the archive view causes problems otherwise. // It also ensures that we scroll to the top when switching views. const listKey = 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. const list = (
{({ height, width }) => ( )}
); return [list]; } public renderHeader(): JSX.Element { return (

{window.i18n('messagesHeader')}

); } public render(): JSX.Element { return (
{this.renderHeader()} {this.state.showComposeView ? this.renderCompose() : this.renderConversations()}
); } public renderCompose(): JSX.Element { return (

{window.i18n('enterRecipient')}

{window.i18n('enterSessionID')}



{window.i18n('usersCanShareTheir...')}
); } public renderConversations() { return (
{this.renderList()}
); } public updateSearch(searchTerm: string) { const { updateSearchTerm, clearSearch } = this.props; if (!searchTerm) { clearSearch(); return; } if (updateSearchTerm) { updateSearchTerm(searchTerm); } if (searchTerm.length < 2) { return; } const cleanedTerm = cleanSearchTerm(searchTerm); if (!cleanedTerm) { return; } this.debouncedSearch(cleanedTerm); } public clearSearch() { const { clearSearch } = this.props; clearSearch(); //this.setFocus(); } public search() { const { search } = this.props; const { searchTerm, isSecondaryDevice } = this.props; if (search) { search(searchTerm, { noteToSelf: window.i18n('noteToSelf').toLowerCase(), ourNumber: window.textsecure.storage.user.getNumber(), regionCode: '', isSecondaryDevice, }); } } private handleComposeClick() { this.setState((state: any) => { return { showComposeView: !state.showComposeView }; }); } private handleOnPasteSessionID() { console.log('handleOnPasteSessionID'); } }