diff options
| author | Eugene Sokolov <eug-vs@keemail.me> | 2020-06-28 04:14:02 +0300 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-06-28 04:14:02 +0300 | 
| commit | 2f1ee1baab72be2ae38a921a7c0da7ce6e03fbc1 (patch) | |
| tree | 3fdca2db655c80907cdef7ac3fdfabed6f78a5ec | |
| parent | 5057fe763d423be607336d6b839909843c5a2567 (diff) | |
| parent | ea9920d9ed0e7b3a3e565623e434e75bd3362f02 (diff) | |
| download | which-ui-2f1ee1baab72be2ae38a921a7c0da7ce6e03fbc1.tar.gz | |
Merge pull request #50 from which-ecosystem/search
SearchBar functionality
| -rw-r--r-- | src/components/Header/Header.tsx | 2 | ||||
| -rw-r--r-- | src/components/Header/SearchBar.tsx | 90 | ||||
| -rw-r--r-- | src/components/UserStrip/UserStrip.tsx | 2 | ||||
| -rw-r--r-- | src/pages/ProfilePage/ProfileInfo.tsx | 22 | 
4 files changed, 104 insertions, 12 deletions
| diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx index 2e3fc20..1825647 100644 --- a/src/components/Header/Header.tsx +++ b/src/components/Header/Header.tsx @@ -52,7 +52,7 @@ const Header: React.FC<PropTypes> = ({ navigate, userImage }) => {          <Typography variant="h5" className={classes.logo}>            Which          </Typography> -        <SearchBar /> +        <SearchBar navigate={navigate} />          <div>            <IconButton onClick={handleHome}>              <HomeIcon /> diff --git a/src/components/Header/SearchBar.tsx b/src/components/Header/SearchBar.tsx index 182a1a4..2be8f6f 100644 --- a/src/components/Header/SearchBar.tsx +++ b/src/components/Header/SearchBar.tsx @@ -1,27 +1,111 @@ -import React from 'react'; +import React, { useState, useEffect } from 'react';  import SearchIcon from '@material-ui/icons/Search'; -import { InputBase } from '@material-ui/core'; +import { +  InputBase, +  List, +  ListItem, +  Paper, +  Divider, +  ClickAwayListener +} from '@material-ui/core';  import { makeStyles } from '@material-ui/core/styles'; +import { User } from 'which-types'; +import { get } from '../../requests'; +import UserStrip from '../UserStrip/UserStrip'; + +interface PropTypes { +  navigate: (prefix: string, id: string) => void; +} + +const INTERVAL = 300;  const useStyles = makeStyles(theme => ({    root: { +    position: 'relative',      background: 'rgba(255, 255, 255, 0.5)',      borderRadius: '2px',      padding: theme.spacing(0.5),      display: 'flex',      alignItems: 'center' +  }, +  results: { +    position: 'absolute', +    width: '100%', +    top: theme.spacing(5)    }  })); -const SearchBar: React.FC = () => { +const SearchBar: React.FC<PropTypes> = ({ navigate }) => { +  const [query, setQuery] = useState<string>(''); +  const [results, setResults] = useState<User[]>([]); +  const [isReady, setIsReady] = useState<boolean>(true); +  const [shouldRefetch, setShouldRefetch] = useState<boolean>(false);    const classes = useStyles(); +  const sleep = () => { +    setIsReady(false); +    setTimeout(() => setIsReady(true), INTERVAL); +  }; + +  const fetchPolls = () => { +    sleep(); +    get(`/users?username[$regex]=${query}`).then(response => { +      setResults(response.data); +    }); +  }; + +  useEffect(() => { +    if (isReady && shouldRefetch) { +      fetchPolls(); +      setShouldRefetch(false); +    } +  }, [isReady]); + + +  const handleChange = (event: React.ChangeEvent<HTMLInputElement>): void => { +    setQuery(event.target.value); +    if (isReady) fetchPolls(); +    else setShouldRefetch(true); +  }; + +  const handleClose = () => { +    setQuery(''); +    setResults([]); +  }; + +  const handleNavigate = (index: number) => () => { +    navigate('profile', results[index]._id); +    handleClose(); +  }; + +  const SearchResults = ( +    <ClickAwayListener onClickAway={handleClose}> +      <Paper className={classes.results}> +        <List> +          { +          results.map((result, index) => ( +            <> +              <ListItem button onClick={handleNavigate(index)}> +                <UserStrip user={result} navigate={navigate} /> +              </ListItem> +              {(index < results.length - 1) && <Divider />} +            </> +          )) +        } +        </List> +      </Paper> +    </ClickAwayListener> +  ); +    return (      <div className={classes.root}>        <SearchIcon />        <InputBase          placeholder="Search..." +        value={query} +        onChange={handleChange}        /> +      {results.length > 0 && SearchResults}      </div>    );  }; diff --git a/src/components/UserStrip/UserStrip.tsx b/src/components/UserStrip/UserStrip.tsx index 6e84768..f02adc3 100644 --- a/src/components/UserStrip/UserStrip.tsx +++ b/src/components/UserStrip/UserStrip.tsx @@ -10,8 +10,8 @@ import { User } from 'which-types';  interface PropTypes {    user: User; -  info: string | JSX.Element    navigate: (prefix: string, id: string) => void; +  info?: string | JSX.Element  } diff --git a/src/pages/ProfilePage/ProfileInfo.tsx b/src/pages/ProfilePage/ProfileInfo.tsx index f52e374..2b9227e 100644 --- a/src/pages/ProfilePage/ProfileInfo.tsx +++ b/src/pages/ProfilePage/ProfileInfo.tsx @@ -1,8 +1,9 @@  import React, { useState } from 'react'; -import { Avatar, Badge } from '@material-ui/core/'; +import { Avatar, Badge, Typography } from '@material-ui/core/';  import { makeStyles } from '@material-ui/core/styles';  import { User } from 'which-types';  import CameraAltIcon from '@material-ui/icons/CameraAlt'; +import VerifiedIcon from '@material-ui/icons/CheckCircleOutline';  import MoreMenu from './MoreMenu';  import Highlight from './Highlight';  import UploadImage from '../../components/UploadImage/UploadImage'; @@ -27,9 +28,15 @@ const useStyles = makeStyles(theme => ({      margin: '0 auto'    },    name: { -    fontSize: 20, -    textAlign: 'center', -    margin: '10px 0' +    margin: theme.spacing(1, 0), +    display: 'flex', +    alignItems: 'center', +    justifyContent: 'center' +  }, +  verified: { +    marginLeft: theme.spacing(0.5), +    width: theme.spacing(3), +    height: theme.spacing(3)    },    profileMenu: {      display: 'flex', @@ -110,13 +117,14 @@ const ProfileInfo: React.FC<PropTypes> = ({  )            : <Avatar className={classes.avatar} src={user?.avatarUrl} />        } -      <div className={classes.name}> +      <Typography variant="h5" className={classes.name}>          {user?.username} -      </div> +        {user?.verified && <VerifiedIcon className={classes.verified} color="primary" />} +      </Typography>        <div className={classes.profileMenu}>          <Highlight text="Polls" value={savedPolls} />          <Highlight text="Since" value={dateSince} /> -        <Highlight text="Total" value={totalVotes} /> +        <Highlight text="Total votes" value={totalVotes} />        </div>      </div>    ); | 
