You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			172 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			TypeScript
		
	
			
		
		
	
	
			172 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			TypeScript
		
	
import React from 'react';
 | 
						|
import { debounce } from 'lodash';
 | 
						|
 | 
						|
import { Avatar } from './Avatar';
 | 
						|
 | 
						|
import { cleanSearchTerm } from '../util/cleanSearchTerm';
 | 
						|
import { LocalizerType } from '../types/Util';
 | 
						|
 | 
						|
export interface Props {
 | 
						|
  searchTerm: string;
 | 
						|
 | 
						|
  // To be used as an ID
 | 
						|
  ourNumber: string;
 | 
						|
  regionCode: string;
 | 
						|
 | 
						|
  // For display
 | 
						|
  phoneNumber: string;
 | 
						|
  isMe: boolean;
 | 
						|
  name?: string;
 | 
						|
  color: string;
 | 
						|
  verified: boolean;
 | 
						|
  profileName?: string;
 | 
						|
  avatarPath?: string;
 | 
						|
 | 
						|
  i18n: LocalizerType;
 | 
						|
  updateSearchTerm: (searchTerm: string) => void;
 | 
						|
  search: (
 | 
						|
    query: string,
 | 
						|
    options: {
 | 
						|
      regionCode: string;
 | 
						|
      ourNumber: string;
 | 
						|
      noteToSelf: string;
 | 
						|
    }
 | 
						|
  ) => void;
 | 
						|
  clearSearch: () => void;
 | 
						|
}
 | 
						|
 | 
						|
export class MainHeader extends React.Component<Props> {
 | 
						|
  private readonly updateSearchBound: (
 | 
						|
    event: React.FormEvent<HTMLInputElement>
 | 
						|
  ) => void;
 | 
						|
  private readonly clearSearchBound: () => void;
 | 
						|
  private readonly handleKeyUpBound: (
 | 
						|
    event: React.KeyboardEvent<HTMLInputElement>
 | 
						|
  ) => void;
 | 
						|
  private readonly setFocusBound: () => void;
 | 
						|
  private readonly inputRef: React.RefObject<HTMLInputElement>;
 | 
						|
  private readonly debouncedSearch: (searchTerm: string) => void;
 | 
						|
 | 
						|
  constructor(props: Props) {
 | 
						|
    super(props);
 | 
						|
 | 
						|
    this.updateSearchBound = this.updateSearch.bind(this);
 | 
						|
    this.clearSearchBound = this.clearSearch.bind(this);
 | 
						|
    this.handleKeyUpBound = this.handleKeyUp.bind(this);
 | 
						|
    this.setFocusBound = this.setFocus.bind(this);
 | 
						|
    this.inputRef = React.createRef();
 | 
						|
 | 
						|
    this.debouncedSearch = debounce(this.search.bind(this), 20);
 | 
						|
  }
 | 
						|
 | 
						|
  public search() {
 | 
						|
    const { searchTerm, search, i18n, ourNumber, regionCode } = this.props;
 | 
						|
    if (search) {
 | 
						|
      search(searchTerm, {
 | 
						|
        noteToSelf: i18n('noteToSelf').toLowerCase(),
 | 
						|
        ourNumber,
 | 
						|
        regionCode,
 | 
						|
      });
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  public updateSearch(event: React.FormEvent<HTMLInputElement>) {
 | 
						|
    const { updateSearchTerm, clearSearch } = this.props;
 | 
						|
    const searchTerm = event.currentTarget.value;
 | 
						|
 | 
						|
    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 handleKeyUp(event: React.KeyboardEvent<HTMLInputElement>) {
 | 
						|
    const { clearSearch } = this.props;
 | 
						|
 | 
						|
    if (event.key === 'Escape') {
 | 
						|
      clearSearch();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  public setFocus() {
 | 
						|
    if (this.inputRef.current) {
 | 
						|
      // @ts-ignore
 | 
						|
      this.inputRef.current.focus();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  public render() {
 | 
						|
    const {
 | 
						|
      searchTerm,
 | 
						|
      avatarPath,
 | 
						|
      i18n,
 | 
						|
      color,
 | 
						|
      name,
 | 
						|
      phoneNumber,
 | 
						|
      profileName,
 | 
						|
    } = this.props;
 | 
						|
 | 
						|
    return (
 | 
						|
      <div className="module-main-header">
 | 
						|
        <Avatar
 | 
						|
          avatarPath={avatarPath}
 | 
						|
          color={color}
 | 
						|
          conversationType="direct"
 | 
						|
          i18n={i18n}
 | 
						|
          name={name}
 | 
						|
          phoneNumber={phoneNumber}
 | 
						|
          profileName={profileName}
 | 
						|
          size={28}
 | 
						|
        />
 | 
						|
        <div className="module-main-header__search">
 | 
						|
          <div
 | 
						|
            role="button"
 | 
						|
            className="module-main-header__search__icon"
 | 
						|
            onClick={this.setFocusBound}
 | 
						|
          />
 | 
						|
          <input
 | 
						|
            type="text"
 | 
						|
            ref={this.inputRef}
 | 
						|
            className="module-main-header__search__input"
 | 
						|
            placeholder={i18n('search')}
 | 
						|
            dir="auto"
 | 
						|
            onKeyUp={this.handleKeyUpBound}
 | 
						|
            value={searchTerm}
 | 
						|
            onChange={this.updateSearchBound}
 | 
						|
          />
 | 
						|
          {searchTerm ? (
 | 
						|
            <div
 | 
						|
              role="button"
 | 
						|
              className="module-main-header__search__cancel-icon"
 | 
						|
              onClick={this.clearSearchBound}
 | 
						|
            />
 | 
						|
          ) : null}
 | 
						|
        </div>
 | 
						|
      </div>
 | 
						|
    );
 | 
						|
  }
 | 
						|
}
 |