aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/components/Header/Header.tsx2
-rw-r--r--src/components/Header/SearchBar.tsx90
-rw-r--r--src/components/UserStrip/UserStrip.tsx2
-rw-r--r--src/pages/ProfilePage/ProfileInfo.tsx22
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>
);