import classNames from "classnames"; import { SearchIcon } from "./icons"; import { useState, useEffect, useRef, useCallback } from "@wordpress/element"; import useSearch from "../../hooks/useSearch"; import { Excerpt } from "../shared/templates/templates-parts/templates-parts"; import { findDataFromArray } from "../../controls/controls"; import useMetaData from "../../hooks/useMetaData"; const Render = ({ attributes }) => { const { displayType, searchResultDisplayType } = attributes; const [isPopupOpen, setIsPopupOpen] = useState(false); return ( <> {"popup" === displayType && (
)} {displayType === "popup" && (
setIsPopupOpen(false)} >
)} ); }; const SmartSearchBody = ({ attributes, isPopupOpen, setIsPopupOpen }) => { const { displayType, popupHeadingText, enablePopupHeading, popupHeadingGlobalTypography, enablePopupCloseButton } = attributes; const { posts, remaining_posts, fetchPosts } = useSearch(attributes); const [isLoading, setIsLoading] = useState(false); const [searchText, setSearchText] = useState(""); const [isShow, setIsShow] = useState(!!searchText && !isLoading); const [popupClass, setPopupClass] = useState(""); const searchRef = useRef(null); useEffect(() => { if (!!searchText && !isLoading) { setIsShow(true); } }, [searchText, isLoading]); useEffect(() => { if (!searchRef.current) { return; } const updatePosition = () => { const rect = searchRef.current.getBoundingClientRect(); const viewportWidth = document.documentElement.clientWidth; if (rect.right > viewportWidth) { setPopupClass("sp-popup-position-right"); } else { setPopupClass("sp-popup-position-left"); } }; updatePosition(); window.addEventListener("resize", updatePosition); return () => { window.removeEventListener("resize", updatePosition); }; }, []); return (
{ // If focus left the entire search wrapper → close dropdown if (!searchRef.current.contains(e.relatedTarget)) { setIsShow(false); } }} className={classNames( "sp-smart-post-search-wrapper", displayType === "popup" && "sp-smart-post-search-popup", isPopupOpen && displayType === "popup" && "sp-smart-post-search-popup--active", popupClass )} > {displayType === "popup" && enablePopupHeading && (

{popupHeadingText}

)} {displayType === "popup" && enablePopupCloseButton && ( setIsPopupOpen(false)}> )} {/* */}
); }; const SearchForm = ({ attributes, setSearchText, setIsLoading, searchText, isLoading, fetchPosts }) => { const { searchFormPreset, placeholder, placeholderEnable, searchBtnLabel, searchIcon, inputPlaceHolderGlobalTypography, selectedTaxonomy, selectedTerms, postType, filterLabelText, taxonomyFilterEnable, searchBtnLabelText, } = attributes; const { allTaxonomies } = useMetaData(attributes, "editSite"); const selectedTaxonomyData = findDataFromArray(allTaxonomies, "name", selectedTaxonomy); const _terms = selectedTaxonomyData?.terms_items.map((item) => ({ ...item, id: item.value, })); const terms = selectedTerms?.length > 0 ? selectedTerms : _terms; const [selectedTerm, setSelectedTerm] = useState(""); const debounceTimer = useRef(null); const inputRef = useRef(null); const handleSearch = useCallback( async (query, term) => { try { setIsLoading(true); await fetchPosts(query, term); } catch (error) { console.log("Error fetching posts:", error.message); } finally { setIsLoading(false); } }, [searchText, selectedTerm, postType] ); useEffect(() => { if (debounceTimer.current) { clearTimeout(debounceTimer.current); } if (searchText) { debounceTimer.current = setTimeout(() => { handleSearch(searchText, selectedTerm); }, 500); } return () => clearTimeout(debounceTimer.current); }, [searchText, handleSearch, postType]); useEffect(() => { if (selectedTerm) { handleSearch(searchText, selectedTerm); } }, [selectedTerm]); const onSubmit = (e) => { e.preventDefault(); handleSearch(searchText, selectedTerm); }; const handleTermChange = (e) => { e.stopPropagation(); const value = e.target.value; if (value) { setSelectedTerm(value); } }; const formHandler = (e) => { e.stopPropagation(); inputRef.current.focus(); }; return (
formHandler ( e )} >
setSearchText(e.target.value)} /> {terms?.length > 0 && postType !== "" && taxonomyFilterEnable && (
)}
); }; const SearchResult = ({ attributes, posts, remaining_posts, isShow }) => { const { searchResultDisplayType, searchResultNotFoundText, moreResultLabelText, moreResultsEnable, showResultsCount, } = attributes; return (
{posts?.length > 0 ? ( posts.map((post, index) => { return ; }) ) : (
{searchResultNotFoundText}
)}
{/* TODO: Need to manage loading state if needed in future */} {/* {isLoading ? (
) : ( <> )} */} {moreResultsEnable && remaining_posts > 0 && (
)}
); }; const SearchItem = ({ post, attributes }) => { const { categories, author, image_alt, post_thumbnail_url, date, excerpt, postTitle } = post; const { searchResultDisplayType, searchResultTitleGlobalTypography, searchResultMetaGlobalTypography, searchResultShowImage, searchResultShowExcerpt, searchResultShowTaxonomy, searchResultExcerptLimit, searchResultShowDate, searchResultShowAuthor, } = attributes; return (
{searchResultDisplayType !== "smart-search-result-layout-two" && searchResultShowImage && (
{image_alt
)}
{searchResultShowTaxonomy && categories?.length > 0 && (
{categories?.map((category, index) => { return ( {category} ); })}
)} {post?.title} {searchResultShowExcerpt && excerpt && ( )} {(searchResultShowDate || searchResultShowAuthor) && (
{author && searchResultShowAuthor && {author}, } {date && searchResultShowDate && {date}}
)}
); }; export default Render;