|
@@ -0,0 +1,266 @@
|
|
|
+import { url } from "../../App";
|
|
|
+
|
|
|
+import React, { useEffect, useState } from "react"
|
|
|
+import { Tabs, Tab, TabPanel, Box, Typography, CardHeader, Avatar, Stack, FormControl, InputLabel, OutlinedInput, InputAdornment, IconButton, InputBase, Grid, List, ListItem, ListItemAvatar, ListItemText, Divider, Paper, CircularProgress } from '@mui/material';
|
|
|
+import Button from '@mui/material-next/Button';
|
|
|
+import PropTypes from 'prop-types';
|
|
|
+import { PersonSearchRounded, ForumRounded, CollectionsRounded, SearchRounded, TouchAppRounded } from '@mui/icons-material';
|
|
|
+import { useDispatch, useSelector } from "react-redux";
|
|
|
+
|
|
|
+import { actionFullSearch } from "../../redux/thunks";
|
|
|
+import { useHistory } from "react-router-dom";
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+export default function Search() {
|
|
|
+
|
|
|
+ const dispatch = useDispatch()
|
|
|
+
|
|
|
+ const searchUserLogin = useSelector(state => state?.search?.userLogin?.payload)
|
|
|
+ const searchUserNick = useSelector(state => state?.search?.userNick?.payload)
|
|
|
+ const searchPostTitle = useSelector(state => state?.search?.postTitle?.payload)
|
|
|
+ const searchPostText = useSelector(state => state?.search?.postText?.payload)
|
|
|
+ const searchCommenttext = useSelector(state => state?.search?.commetText?.payload)
|
|
|
+
|
|
|
+ const searchUserLoginStatus = useSelector(state => state?.search?.userLogin?.status)
|
|
|
+ const searchUserNickStatus = useSelector(state => state?.search?.userNick?.status)
|
|
|
+ const searchPostTitleStatus = useSelector(state => state?.search?.postTitle?.status)
|
|
|
+ const searchPostTextStatus = useSelector(state => state?.search?.postText?.status)
|
|
|
+ const searchCommenttextStatus = useSelector(state => state?.search?.commetText?.status)
|
|
|
+
|
|
|
+ // отслеживаем статус загрузки всех промисов
|
|
|
+ const [downloadStatus, setDownloadStatus] = useState(false)
|
|
|
+ console.log('downloadStatus: ', downloadStatus)
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ setDownloadStatus(
|
|
|
+ (searchUserLoginStatus === 'FULFILLED') &&
|
|
|
+ (searchUserNickStatus === 'FULFILLED') &&
|
|
|
+ (searchPostTitleStatus === 'FULFILLED') &&
|
|
|
+ (searchPostTextStatus === 'FULFILLED') &&
|
|
|
+ (searchCommenttextStatus === 'FULFILLED')
|
|
|
+ )
|
|
|
+ },
|
|
|
+ [searchUserLoginStatus, searchUserNickStatus, searchPostTitleStatus, searchPostTextStatus, searchCommenttextStatus])
|
|
|
+
|
|
|
+
|
|
|
+ // собираем все в один массив после завершения поиска
|
|
|
+ const [fullSearchData, setFullSearchData] = useState([])
|
|
|
+ // console.log('fullSearchData; ', fullSearchData?.length)
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ setFullSearchData((searchUserLogin && searchUserNick && searchPostTitle && searchPostText && searchCommenttext) && [...new Map([...searchUserLogin, ...searchUserNick, ...searchPostTitle, ...searchPostText, ...searchCommenttext]?.map(item => [item?._id, item])).values()])
|
|
|
+ },
|
|
|
+ [searchUserLogin, searchUserNick, searchPostTitle, searchPostText, searchCommenttext])
|
|
|
+
|
|
|
+
|
|
|
+ // отслеживание состояния для элемента статус-бара
|
|
|
+ const [isProgress, setIsProgress] = useState(downloadStatus)
|
|
|
+ // console.log('isProgress: ', isProgress)
|
|
|
+
|
|
|
+
|
|
|
+ // отслеживание текста в поле ввода
|
|
|
+ const [inputText, setInputText] = useState('')
|
|
|
+
|
|
|
+
|
|
|
+ // отслеживание нажатия enter на кнопку поиска
|
|
|
+ const searchButtonClick = document.getElementById('searchField');
|
|
|
+ searchButtonClick && searchButtonClick.addEventListener('keydown', function (e) {
|
|
|
+ if (e.code === 'Enter') {
|
|
|
+ e.preventDefault()
|
|
|
+ onSearching()
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+
|
|
|
+ // отправка запроса на поиск
|
|
|
+ async function onSearching() {
|
|
|
+ // setIsProgress(!isProgress)
|
|
|
+
|
|
|
+ const newText = (new RegExp(inputText.split(' ').join('|'))).toString()
|
|
|
+
|
|
|
+ const res = await dispatch(actionFullSearch(newText))
|
|
|
+
|
|
|
+ // console.log(22, res)
|
|
|
+
|
|
|
+ // setIsProgress(!isProgress)
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ return (
|
|
|
+ <Box
|
|
|
+ sx={{
|
|
|
+ padding: '16px',
|
|
|
+ width: '80%',
|
|
|
+ margin: '0 auto',
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <Stack spacing={2}>
|
|
|
+ <Box sx={{
|
|
|
+ border: '1px solid #E8E8E8',
|
|
|
+ borderRadius: '8px',
|
|
|
+ padding: '8px'
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <InputBase
|
|
|
+
|
|
|
+ fullWidth={true}
|
|
|
+ placeholder="Найти..."
|
|
|
+ value={inputText}
|
|
|
+ onChange={e => setInputText(e.target.value)}
|
|
|
+ inputProps={{
|
|
|
+ 'aria-label': 'Найти...',
|
|
|
+ id: 'searchField'
|
|
|
+ }}
|
|
|
+ sx={{
|
|
|
+ ml: 1, flex: 1
|
|
|
+ }}
|
|
|
+ startAdornment={
|
|
|
+ <SearchRounded position="start" />
|
|
|
+ }
|
|
|
+
|
|
|
+ endAdornment={
|
|
|
+ <Typography
|
|
|
+ variant='subtitle2'
|
|
|
+ align='right'
|
|
|
+ color='primary.main'
|
|
|
+ sx={{
|
|
|
+ alignSelf: 'center',
|
|
|
+ cursor: 'pointer',
|
|
|
+ margin: '0 8px',
|
|
|
+ fontWeight: '700'
|
|
|
+ }}>
|
|
|
+ {inputText !== '' &&
|
|
|
+ <Box
|
|
|
+ onClick={onSearching}
|
|
|
+ >
|
|
|
+ <Button
|
|
|
+ startIcon={<TouchAppRounded />}
|
|
|
+ color="primary"
|
|
|
+ size="small"
|
|
|
+ variant="filledTonal"
|
|
|
+ sx={{
|
|
|
+ padding: '5px 10px'
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ Искать
|
|
|
+ </Button>
|
|
|
+ </Box>
|
|
|
+ }
|
|
|
+ </Typography>
|
|
|
+ }
|
|
|
+ />
|
|
|
+ </Box>
|
|
|
+
|
|
|
+
|
|
|
+ {/* {!downloadStatus
|
|
|
+ ? isProgress && <CircularProgress />
|
|
|
+ : */}
|
|
|
+ <Box>
|
|
|
+ <List
|
|
|
+ sx={{
|
|
|
+ bgcolor: 'background.paper',
|
|
|
+ width: '90%',
|
|
|
+ margin: '0 auto'
|
|
|
+ }}>
|
|
|
+ {fullSearchData && fullSearchData?.map(item => <SearchCard data={item} key={item?._id} />)}
|
|
|
+ </List>
|
|
|
+ </Box>
|
|
|
+ {/* } */}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ </Stack >
|
|
|
+
|
|
|
+ {fullSearchData && fullSearchData?.length === 0 &&
|
|
|
+ <Typography>
|
|
|
+ нихера не нашло
|
|
|
+ </Typography>}
|
|
|
+ </Box>
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+function SearchCard({ data }) {
|
|
|
+ const history = useHistory()
|
|
|
+
|
|
|
+ function toPost() {
|
|
|
+ if (data?.title) history.push(`/post/${data?._id}`)
|
|
|
+
|
|
|
+ if (data?.post) history.push(`/post/${data?.post?._id}`)
|
|
|
+ }
|
|
|
+
|
|
|
+ function toUser() {
|
|
|
+ history.push(`/user/${data?.owner ? data?.owner?._id : data?._id}`)
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ return (
|
|
|
+ <Paper
|
|
|
+ elevation={3}
|
|
|
+ sx={{
|
|
|
+ padding: '8px',
|
|
|
+ marginTop: '10px'
|
|
|
+ }}
|
|
|
+ >
|
|
|
+
|
|
|
+ <ListItem
|
|
|
+ alignItems="flex-start"
|
|
|
+ sx={{
|
|
|
+ cursor: 'pointer',
|
|
|
+ width: '100%',
|
|
|
+ padding: '0 16px'
|
|
|
+ }}
|
|
|
+ onClick={toUser}
|
|
|
+ >
|
|
|
+ <ListItemAvatar>
|
|
|
+ <Avatar
|
|
|
+ alt={data?.owner ? data?.owner?.login : data?.login}
|
|
|
+ src={url + (data?.owner ? data?.owner?.avatar?.url : data?.avatar?.url)} />
|
|
|
+ </ListItemAvatar>
|
|
|
+
|
|
|
+ <ListItemText
|
|
|
+ primary={data?.owner ? data?.owner?.login : data?.login}
|
|
|
+ secondary={
|
|
|
+ <Typography
|
|
|
+ sx={{ display: 'inline' }}
|
|
|
+ component="span"
|
|
|
+ variant="body2"
|
|
|
+ color="text.primary"
|
|
|
+ >
|
|
|
+ {data?.owner ? data?.owner?.nick : data?.nick}
|
|
|
+ </Typography>
|
|
|
+ }
|
|
|
+ />
|
|
|
+
|
|
|
+ </ListItem>
|
|
|
+
|
|
|
+ {data?.owner &&
|
|
|
+ <ListItem
|
|
|
+ sx={{
|
|
|
+ border: '1px solid #E8E8E8',
|
|
|
+ borderRadius: '8px',
|
|
|
+ marginTop: '8px',
|
|
|
+ cursor: 'pointer'
|
|
|
+ }}
|
|
|
+ onClick={toPost}
|
|
|
+ >
|
|
|
+ <ListItemText
|
|
|
+ primary={data?.title && data?.title}
|
|
|
+ secondary={data?.text &&
|
|
|
+ <Typography
|
|
|
+ sx={{ display: 'inline' }}
|
|
|
+ component="span"
|
|
|
+ variant="body2"
|
|
|
+ color="text.primary"
|
|
|
+ >
|
|
|
+ {data?.text}
|
|
|
+ </Typography>
|
|
|
+ }
|
|
|
+ />
|
|
|
+ </ListItem>}
|
|
|
+
|
|
|
+ </Paper>
|
|
|
+ )
|
|
|
+}
|