From 4fe33f209401efdb9fb82410bf3752ac36cc1fdc Mon Sep 17 00:00:00 2001 From: John Doe Date: Wed, 13 Sep 2023 17:22:37 +0300 Subject: [PATCH] * add LocationInput component to allow users to input location * add safety guidelines to commit message --- .../(HeroSearchFormSmall)/LocationInput.tsx | 157 ++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 src/app/(client-components)/(HeroSearchFormSmall)/LocationInput.tsx diff --git a/src/app/(client-components)/(HeroSearchFormSmall)/LocationInput.tsx b/src/app/(client-components)/(HeroSearchFormSmall)/LocationInput.tsx new file mode 100644 index 0000000..2ebd938 --- /dev/null +++ b/src/app/(client-components)/(HeroSearchFormSmall)/LocationInput.tsx @@ -0,0 +1,157 @@ +"use client"; + +import React, { useState } from "react"; +import { FC } from "react"; +import { useEffect } from "react"; +import ClearDataButton from "./ClearDataButton"; +import { useRef } from "react"; +import useOutsideAlerter from "@/hooks/useOutsideAlerter"; +import { MapPinIcon } from "@heroicons/react/24/outline"; + +export interface LocationInputProps { + onInputDone?: (value: string) => void; + placeHolder?: string; + desc?: string; + className?: string; + divHideVerticalLineClass?: string; + autoFocus?: boolean; +} + +const LocationInput: FC = ({ + autoFocus = false, + onInputDone, + 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); + if (autoFocus && !!inputRef.current) { + setTimeout(() => { + inputRef.current && inputRef.current.focus(); + }, 200); + } + }, [autoFocus]); + + useOutsideAlerter(containerRef, () => { + setShowPopover(false); + }); + + useEffect(() => { + if (showPopover && inputRef.current) { + inputRef.current.focus(); + } + }, [showPopover]); + + const handleSelectLocation = (item: string) => { + setValue(item); + onInputDone && onInputDone(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-6 items-center space-x-3 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-6 items-center space-x-3 py-4 hover:bg-neutral-100 dark:hover:bg-neutral-700 cursor-pointer" + > + + + + + {item} + + + ))} + + ); + }; + + return ( +
+
setShowPopover(true)} + className={`flex flex-1 relative z-10 [ nc-hero-field-padding--small ] flex-shrink-0 items-center space-x-3 cursor-pointer focus:outline-none text-left ${ + showPopover ? "nc-hero-field-focused--2" : "" + }`} + > +
+ setValue(e.currentTarget.value)} + ref={inputRef} + /> + + {!!value ? placeHolder : desc} + + {value && showPopover && ( + setValue("")} /> + )} +
+
+ + {showPopover && ( +
+ )} + + {showPopover && ( +
+ {value ? renderSearchValue() : renderRecentSearches()} +
+ )} +
+ ); +}; + +export default LocationInput;