From 04833c27efdf353eee83bff53ceab857741c31b9 Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 13 Sep 2023 19:34:20 +0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A7=20Refactor=20component=20for=20bet?= =?UTF-8?q?ter=20usability=20=F0=9F=90=9E=20Fix=20issue=20with=20recent=20?= =?UTF-8?q?searches=20=F0=9F=9A=80=20Implement=20new=20features=20?= =?UTF-8?q?=F0=9F=91=8C=20Improve=20code=20readability=20and=20structure?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../(HeroSearchForm)/LocationInput.tsx | 171 ++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 src/app/(client-components)/(HeroSearchForm)/LocationInput.tsx diff --git a/src/app/(client-components)/(HeroSearchForm)/LocationInput.tsx b/src/app/(client-components)/(HeroSearchForm)/LocationInput.tsx new file mode 100644 index 0000000..ea6c49d --- /dev/null +++ b/src/app/(client-components)/(HeroSearchForm)/LocationInput.tsx @@ -0,0 +1,171 @@ +"use client"; + +import { ClockIcon, MapPinIcon } from "@heroicons/react/24/outline"; +import React, { useState, useRef, useEffect, FC } from "react"; +import ClearDataButton from "./ClearDataButton"; + +export interface LocationInputProps { + placeHolder?: string; + desc?: string; + className?: string; + divHideVerticalLineClass?: string; + autoFocus?: boolean; +} + +const LocationInput: FC = ({ + autoFocus = false, + placeHolder = "Location", + desc = "Where are you going?", + className = "nc-flex-1.5", + divHideVerticalLineClass = "left-10 -right-0.5", +}) => { + const containerRef = useRef(null); + const inputRef = useRef(null); + + const [value, setValue] = useState(""); + const [showPopover, setShowPopover] = useState(autoFocus); + + useEffect(() => { + setShowPopover(autoFocus); + }, [autoFocus]); + + useEffect(() => { + if (eventClickOutsideDiv) { + document.removeEventListener("click", eventClickOutsideDiv); + } + showPopover && document.addEventListener("click", eventClickOutsideDiv); + return () => { + document.removeEventListener("click", eventClickOutsideDiv); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [showPopover]); + + useEffect(() => { + if (showPopover && inputRef.current) { + inputRef.current.focus(); + } + }, [showPopover]); + + const eventClickOutsideDiv = (event: MouseEvent) => { + if (!containerRef.current) return; + // CLICK IN_SIDE + if (!showPopover || containerRef.current.contains(event.target as Node)) { + return; + } + // CLICK OUT_SIDE + setShowPopover(false); + }; + + const handleSelectLocation = (item: string) => { + setValue(item); + setShowPopover(false); + }; + + const renderRecentSearches = () => { + return ( + <> +

+ Recent searches +

+
+ {[ + "Hamptons, Suffolk County, NY", + "Las Vegas, NV, United States", + "Ueno, Taito, Tokyo", + "Ikebukuro, Toshima, Tokyo", + ].map((item) => ( + handleSelectLocation(item)} + key={item} + className="flex px-4 sm:px-8 items-center space-x-3 sm:space-x-4 py-4 hover:bg-neutral-100 dark:hover:bg-neutral-700 cursor-pointer" + > + + + + + {item} + + + ))} +
+ + ); + }; + + const renderSearchValue = () => { + return ( + <> + {[ + "Ha Noi, Viet Nam", + "San Diego, CA", + "Humboldt Park, Chicago, IL", + "Bangor, Northern Ireland", + ].map((item) => ( + handleSelectLocation(item)} + key={item} + className="flex px-4 sm:px-8 items-center space-x-3 sm:space-x-4 py-4 hover:bg-neutral-100 dark:hover:bg-neutral-700 cursor-pointer" + > + + + + + {item} + + + ))} + + ); + }; + + return ( +
+
setShowPopover(true)} + className={`flex z-10 flex-1 relative [ nc-hero-field-padding ] flex-shrink-0 items-center space-x-3 cursor-pointer focus:outline-none text-left ${ + showPopover ? "nc-hero-field-focused" : "" + }`} + > +
+ +
+
+ { + setValue(e.currentTarget.value); + }} + ref={inputRef} + /> + + {!!value ? placeHolder : desc} + + {value && showPopover && ( + { + setValue(""); + }} + /> + )} +
+
+ + {showPopover && ( +
+ )} + + {showPopover && ( +
+ {value ? renderSearchValue() : renderRecentSearches()} +
+ )} +
+ ); +}; + +export default LocationInput;