SearchBar.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. import { useEffect, useState, useRef } from "react";
  2. import { connect } from "react-redux";
  3. import { AiOutlineCloseCircle } from "react-icons/ai";
  4. import { Box, TextField, Button, Stack, IconButton } from "@mui/material";
  5. import { actionGoodsFind } from "../../../actions/actionGoodsFind";
  6. import { useLocation, useSearchParams } from "react-router-dom";
  7. import { actionPromiseClear } from "../../../reducers";
  8. export const SearchBar = ({
  9. onSearchEnd,
  10. onSearch,
  11. onSearchButtonClick,
  12. render = null,
  13. renderParams = {},
  14. searchLink = "/search/",
  15. } = {}) => {
  16. const ref = useRef();
  17. const location = useLocation();
  18. const [searchParams] = useSearchParams();
  19. const [inputValue, setInputValue] = useState("");
  20. const [isChildrenOpen, setIsChildrenOpen] = useState(false);
  21. const [touched, setTouched] = useState(false);
  22. const R = render;
  23. const handleOnClick = () => {
  24. if (!inputValue.trim().length) {
  25. return;
  26. }
  27. onSearchButtonClick(inputValue);
  28. setInputValue("");
  29. onSearchEnd && onSearchEnd();
  30. setIsChildrenOpen(false);
  31. setTouched(false);
  32. };
  33. useEffect(() => {
  34. return () => {
  35. onSearchEnd && onSearchEnd();
  36. };
  37. }, []);
  38. useEffect(() => {
  39. setInputValue((searchLink === location.pathname && searchParams.get("text")) || "");
  40. }, [searchParams]);
  41. useEffect(() => {
  42. const checkClickOutsideHeaderSearchBar = (e) => {
  43. if (ref.current && !ref.current.contains(e.target)) {
  44. setIsChildrenOpen(false);
  45. } else {
  46. inputValue.length && setIsChildrenOpen(true);
  47. }
  48. };
  49. inputValue && onSearch(inputValue);
  50. touched && setIsChildrenOpen(!!inputValue?.length);
  51. document.addEventListener("mousedown", checkClickOutsideHeaderSearchBar);
  52. return () => {
  53. document.removeEventListener("mousedown", checkClickOutsideHeaderSearchBar);
  54. };
  55. }, [inputValue]);
  56. return (
  57. <Box className={`SearchBar ${!isChildrenOpen && "hide"}`} ref={ref}>
  58. <Stack direction="row" alignItems="center">
  59. <TextField
  60. variant="standard"
  61. value={inputValue}
  62. placeholder="Пошук"
  63. onChange={(e) => setInputValue(e.target.value)}
  64. onKeyDown={(e) => e.key === "Enter" && handleOnClick()}
  65. className="SearchBarInput"
  66. onBlur={() => setTouched(true)}
  67. onClick={() => setTouched(true)}
  68. InputProps={{
  69. endAdornment: (
  70. <IconButton onClick={() => setInputValue("")} edge="end">
  71. {inputValue && <AiOutlineCloseCircle />}
  72. </IconButton>
  73. ),
  74. }}
  75. />
  76. {!!inputValue ? (
  77. <Button className="Link" onClick={handleOnClick} variant="text" color="inherit">
  78. Пошук
  79. </Button>
  80. ) : (
  81. <Button variant="text" color="inherit">
  82. Пошук
  83. </Button>
  84. )}
  85. </Stack>
  86. <Stack direction="row">
  87. {isChildrenOpen && (
  88. <R
  89. onItemClick={() => {
  90. setInputValue("");
  91. onSearchEnd && onSearchEnd();
  92. }}
  93. {...renderParams}
  94. />
  95. )}
  96. </Stack>
  97. </Box>
  98. );
  99. };
  100. export const CSearchBar = connect(null, {
  101. onSearch: (text) => actionGoodsFind({ text, limit: 5, delay: 1500 }),
  102. onSearchEnd: () => actionPromiseClear("goodsFind"),
  103. })(SearchBar);