test.js 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. import { url } from "../../App";
  2. import React, { useEffect, useState } from "react"
  3. 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';
  4. import Button from '@mui/material-next/Button';
  5. import PropTypes from 'prop-types';
  6. import { PersonSearchRounded, ForumRounded, CollectionsRounded, SearchRounded, TouchAppRounded } from '@mui/icons-material';
  7. import { useDispatch, useSelector } from "react-redux";
  8. import { actionFullSearch } from "../../redux/thunks";
  9. import { useHistory } from "react-router-dom";
  10. export default function Search() {
  11. const dispatch = useDispatch()
  12. const searchUserLogin = useSelector(state => state?.search?.userLogin?.payload)
  13. const searchUserNick = useSelector(state => state?.search?.userNick?.payload)
  14. const searchPostTitle = useSelector(state => state?.search?.postTitle?.payload)
  15. const searchPostText = useSelector(state => state?.search?.postText?.payload)
  16. const searchCommenttext = useSelector(state => state?.search?.commetText?.payload)
  17. const searchUserLoginStatus = useSelector(state => state?.search?.userLogin?.status)
  18. const searchUserNickStatus = useSelector(state => state?.search?.userNick?.status)
  19. const searchPostTitleStatus = useSelector(state => state?.search?.postTitle?.status)
  20. const searchPostTextStatus = useSelector(state => state?.search?.postText?.status)
  21. const searchCommenttextStatus = useSelector(state => state?.search?.commetText?.status)
  22. // отслеживаем статус загрузки всех промисов
  23. const [downloadStatus, setDownloadStatus] = useState(false)
  24. console.log('downloadStatus: ', downloadStatus)
  25. useEffect(() => {
  26. setDownloadStatus(
  27. (searchUserLoginStatus === 'FULFILLED') &&
  28. (searchUserNickStatus === 'FULFILLED') &&
  29. (searchPostTitleStatus === 'FULFILLED') &&
  30. (searchPostTextStatus === 'FULFILLED') &&
  31. (searchCommenttextStatus === 'FULFILLED')
  32. )
  33. },
  34. [searchUserLoginStatus, searchUserNickStatus, searchPostTitleStatus, searchPostTextStatus, searchCommenttextStatus])
  35. // собираем все в один массив после завершения поиска
  36. const [fullSearchData, setFullSearchData] = useState([])
  37. // console.log('fullSearchData; ', fullSearchData?.length)
  38. useEffect(() => {
  39. setFullSearchData((searchUserLogin && searchUserNick && searchPostTitle && searchPostText && searchCommenttext) && [...new Map([...searchUserLogin, ...searchUserNick, ...searchPostTitle, ...searchPostText, ...searchCommenttext]?.map(item => [item?._id, item])).values()])
  40. },
  41. [searchUserLogin, searchUserNick, searchPostTitle, searchPostText, searchCommenttext])
  42. // отслеживание состояния для элемента статус-бара
  43. const [isProgress, setIsProgress] = useState(downloadStatus)
  44. // console.log('isProgress: ', isProgress)
  45. // отслеживание текста в поле ввода
  46. const [inputText, setInputText] = useState('')
  47. // отслеживание нажатия enter на кнопку поиска
  48. const searchButtonClick = document.getElementById('searchField');
  49. searchButtonClick && searchButtonClick.addEventListener('keydown', function (e) {
  50. if (e.code === 'Enter') {
  51. e.preventDefault()
  52. onSearching()
  53. }
  54. })
  55. // отправка запроса на поиск
  56. async function onSearching() {
  57. // setIsProgress(!isProgress)
  58. const newText = (new RegExp(inputText.split(' ').join('|'))).toString()
  59. const res = await dispatch(actionFullSearch(newText))
  60. // console.log(22, res)
  61. // setIsProgress(!isProgress)
  62. }
  63. return (
  64. <Box
  65. sx={{
  66. padding: '16px',
  67. width: '80%',
  68. margin: '0 auto',
  69. }}
  70. >
  71. <Stack spacing={2}>
  72. <Box sx={{
  73. border: '1px solid #E8E8E8',
  74. borderRadius: '8px',
  75. padding: '8px'
  76. }}
  77. >
  78. <InputBase
  79. fullWidth={true}
  80. placeholder="Найти..."
  81. value={inputText}
  82. onChange={e => setInputText(e.target.value)}
  83. inputProps={{
  84. 'aria-label': 'Найти...',
  85. id: 'searchField'
  86. }}
  87. sx={{
  88. ml: 1, flex: 1
  89. }}
  90. startAdornment={
  91. <SearchRounded position="start" />
  92. }
  93. endAdornment={
  94. <Typography
  95. variant='subtitle2'
  96. align='right'
  97. color='primary.main'
  98. sx={{
  99. alignSelf: 'center',
  100. cursor: 'pointer',
  101. margin: '0 8px',
  102. fontWeight: '700'
  103. }}>
  104. {inputText !== '' &&
  105. <Box
  106. onClick={onSearching}
  107. >
  108. <Button
  109. startIcon={<TouchAppRounded />}
  110. color="primary"
  111. size="small"
  112. variant="filledTonal"
  113. sx={{
  114. padding: '5px 10px'
  115. }}
  116. >
  117. Искать
  118. </Button>
  119. </Box>
  120. }
  121. </Typography>
  122. }
  123. />
  124. </Box>
  125. {/* {!downloadStatus
  126. ? isProgress && <CircularProgress />
  127. : */}
  128. <Box>
  129. <List
  130. sx={{
  131. bgcolor: 'background.paper',
  132. width: '90%',
  133. margin: '0 auto'
  134. }}>
  135. {fullSearchData && fullSearchData?.map(item => <SearchCard data={item} key={item?._id} />)}
  136. </List>
  137. </Box>
  138. {/* } */}
  139. </Stack >
  140. {fullSearchData && fullSearchData?.length === 0 &&
  141. <Typography>
  142. нихера не нашло
  143. </Typography>}
  144. </Box>
  145. )
  146. }
  147. function SearchCard({ data }) {
  148. const history = useHistory()
  149. function toPost() {
  150. if (data?.title) history.push(`/post/${data?._id}`)
  151. if (data?.post) history.push(`/post/${data?.post?._id}`)
  152. }
  153. function toUser() {
  154. history.push(`/user/${data?.owner ? data?.owner?._id : data?._id}`)
  155. }
  156. return (
  157. <Paper
  158. elevation={3}
  159. sx={{
  160. padding: '8px',
  161. marginTop: '10px'
  162. }}
  163. >
  164. <ListItem
  165. alignItems="flex-start"
  166. sx={{
  167. cursor: 'pointer',
  168. width: '100%',
  169. padding: '0 16px'
  170. }}
  171. onClick={toUser}
  172. >
  173. <ListItemAvatar>
  174. <Avatar
  175. alt={data?.owner ? data?.owner?.login : data?.login}
  176. src={url + (data?.owner ? data?.owner?.avatar?.url : data?.avatar?.url)} />
  177. </ListItemAvatar>
  178. <ListItemText
  179. primary={data?.owner ? data?.owner?.login : data?.login}
  180. secondary={
  181. <Typography
  182. sx={{ display: 'inline' }}
  183. component="span"
  184. variant="body2"
  185. color="text.primary"
  186. >
  187. {data?.owner ? data?.owner?.nick : data?.nick}
  188. </Typography>
  189. }
  190. />
  191. </ListItem>
  192. {data?.owner &&
  193. <ListItem
  194. sx={{
  195. border: '1px solid #E8E8E8',
  196. borderRadius: '8px',
  197. marginTop: '8px',
  198. cursor: 'pointer'
  199. }}
  200. onClick={toPost}
  201. >
  202. <ListItemText
  203. primary={data?.title && data?.title}
  204. secondary={data?.text &&
  205. <Typography
  206. sx={{ display: 'inline' }}
  207. component="span"
  208. variant="body2"
  209. color="text.primary"
  210. >
  211. {data?.text}
  212. </Typography>
  213. }
  214. />
  215. </ListItem>}
  216. </Paper>
  217. )
  218. }