Browse Source
🚀 Implemented flight class selection
🚀 Implemented flight class selection
💼 Added guest count input fields 🗺️ Improved location inputs 📅 Enhanced date range selection 🔧 Minor code refactor and cleanupmain
John Doe
1 year ago
1 changed files with 246 additions and 0 deletions
@ -0,0 +1,246 @@ |
|||
"use client"; |
|||
|
|||
import React, { FC, useState } from "react"; |
|||
import LocationInput from "../LocationInput"; |
|||
import { Popover, Transition } from "@headlessui/react"; |
|||
import { ChevronDownIcon } from "@heroicons/react/24/solid"; |
|||
import { Fragment } from "react"; |
|||
import NcInputNumber from "@/components/NcInputNumber"; |
|||
import FlightDateRangeInput from "./FlightDateRangeInput"; |
|||
import { GuestsObject } from "../../type"; |
|||
|
|||
export interface FlightSearchFormProps {} |
|||
|
|||
const flightClass = [ |
|||
{ |
|||
name: "Economy", |
|||
href: "##", |
|||
}, |
|||
{ |
|||
name: "Business", |
|||
href: "##", |
|||
}, |
|||
{ |
|||
name: "Multiple", |
|||
href: "##", |
|||
}, |
|||
]; |
|||
|
|||
export type TypeDropOffLocationType = "roundTrip" | "oneWay" | ""; |
|||
|
|||
const FlightSearchForm: FC<FlightSearchFormProps> = ({}) => { |
|||
const [dropOffLocationType, setDropOffLocationType] = |
|||
useState<TypeDropOffLocationType>("roundTrip"); |
|||
const [flightClassState, setFlightClassState] = useState("Economy"); |
|||
|
|||
const [guestAdultsInputValue, setGuestAdultsInputValue] = useState(2); |
|||
const [guestChildrenInputValue, setGuestChildrenInputValue] = useState(1); |
|||
const [guestInfantsInputValue, setGuestInfantsInputValue] = useState(1); |
|||
|
|||
const handleChangeData = (value: number, type: keyof GuestsObject) => { |
|||
let newValue = { |
|||
guestAdults: guestAdultsInputValue, |
|||
guestChildren: guestChildrenInputValue, |
|||
guestInfants: guestInfantsInputValue, |
|||
}; |
|||
if (type === "guestAdults") { |
|||
setGuestAdultsInputValue(value); |
|||
newValue.guestAdults = value; |
|||
} |
|||
if (type === "guestChildren") { |
|||
setGuestChildrenInputValue(value); |
|||
newValue.guestChildren = value; |
|||
} |
|||
if (type === "guestInfants") { |
|||
setGuestInfantsInputValue(value); |
|||
newValue.guestInfants = value; |
|||
} |
|||
}; |
|||
|
|||
const totalGuests = |
|||
guestChildrenInputValue + guestAdultsInputValue + guestInfantsInputValue; |
|||
|
|||
const renderGuest = () => { |
|||
return ( |
|||
<Popover className="relative"> |
|||
{({ open }) => ( |
|||
<> |
|||
<Popover.Button |
|||
as="button" |
|||
className={`
|
|||
${open ? "" : ""} |
|||
px-4 py-1.5 rounded-md inline-flex items-center font-medium hover:text-opacity-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 text-xs`}
|
|||
> |
|||
<span>{`${totalGuests || ""} Guests`}</span> |
|||
<ChevronDownIcon |
|||
className={`${ |
|||
open ? "" : "text-opacity-70" |
|||
} ml-2 h-4 w-4 group-hover:text-opacity-80 transition ease-in-out duration-150`}
|
|||
aria-hidden="true" |
|||
/> |
|||
</Popover.Button> |
|||
<Transition |
|||
as={Fragment} |
|||
enter="transition ease-out duration-200" |
|||
enterFrom="opacity-0 translate-y-1" |
|||
enterTo="opacity-100 translate-y-0" |
|||
leave="transition ease-in duration-150" |
|||
leaveFrom="opacity-100 translate-y-0" |
|||
leaveTo="opacity-0 translate-y-1" |
|||
> |
|||
<Popover.Panel className="absolute z-20 w-full sm:min-w-[340px] max-w-sm bg-white dark:bg-neutral-800 top-full mt-3 left-1/2 -translate-x-1/2 py-5 sm:py-6 px-4 sm:px-8 rounded-3xl shadow-xl ring-1 ring-black/5 dark:ring-white/10"> |
|||
<NcInputNumber |
|||
className="w-full" |
|||
defaultValue={guestAdultsInputValue} |
|||
onChange={(value) => handleChangeData(value, "guestAdults")} |
|||
max={10} |
|||
min={1} |
|||
label="Adults" |
|||
desc="Ages 13 or above" |
|||
/> |
|||
<NcInputNumber |
|||
className="w-full mt-6" |
|||
defaultValue={guestChildrenInputValue} |
|||
onChange={(value) => handleChangeData(value, "guestChildren")} |
|||
max={4} |
|||
label="Children" |
|||
desc="Ages 2–12" |
|||
/> |
|||
|
|||
<NcInputNumber |
|||
className="w-full mt-6" |
|||
defaultValue={guestInfantsInputValue} |
|||
onChange={(value) => handleChangeData(value, "guestInfants")} |
|||
max={4} |
|||
label="Infants" |
|||
desc="Ages 0–2" |
|||
/> |
|||
</Popover.Panel> |
|||
</Transition> |
|||
</> |
|||
)} |
|||
</Popover> |
|||
); |
|||
}; |
|||
|
|||
const renderSelectClass = () => { |
|||
return ( |
|||
<Popover className="relative"> |
|||
{({ open, close }) => ( |
|||
<> |
|||
<Popover.Button |
|||
className={`
|
|||
${open ? "" : ""} |
|||
px-4 py-1.5 rounded-md inline-flex items-center font-medium hover:text-opacity-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 text-xs`}
|
|||
> |
|||
<span>{`${flightClassState}`}</span> |
|||
<ChevronDownIcon |
|||
className={`${ |
|||
open ? "" : "text-opacity-70" |
|||
} ml-2 h-4 w-4 group-hover:text-opacity-80 transition ease-in-out duration-150`}
|
|||
aria-hidden="true" |
|||
/> |
|||
</Popover.Button> |
|||
<Transition |
|||
as={Fragment} |
|||
enter="transition ease-out duration-200" |
|||
enterFrom="opacity-0 translate-y-1" |
|||
enterTo="opacity-100 translate-y-0" |
|||
leave="transition ease-in duration-150" |
|||
leaveFrom="opacity-100 translate-y-0" |
|||
leaveTo="opacity-0 translate-y-1" |
|||
> |
|||
<Popover.Panel className="absolute z-20 w-screen max-w-[200px] sm:max-w-[220px] px-4 top-full mt-3 transform -translate-x-1/2 left-1/2 sm:px-0 "> |
|||
<div className="overflow-hidden rounded-2xl shadow-lg ring-1 ring-black/5 dark:ring-white/10 "> |
|||
<div className="relative grid gap-8 bg-white dark:bg-neutral-800 p-7 "> |
|||
{flightClass.map((item) => ( |
|||
<a |
|||
key={item.name} |
|||
href={item.href} |
|||
onClick={(e) => { |
|||
e.preventDefault(); |
|||
setFlightClassState(item.name); |
|||
close(); |
|||
}} |
|||
className="flex items-center p-2 -m-3 transition duration-150 ease-in-out rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 focus:outline-none focus-visible:ring focus-visible:ring-orange-500 focus-visible:ring-opacity-50" |
|||
> |
|||
<p className="text-sm font-medium ">{item.name}</p> |
|||
</a> |
|||
))} |
|||
</div> |
|||
</div> |
|||
</Popover.Panel> |
|||
</Transition> |
|||
</> |
|||
)} |
|||
</Popover> |
|||
); |
|||
}; |
|||
|
|||
const renderRadioBtn = () => { |
|||
return ( |
|||
<div className=" py-5 [ nc-hero-field-padding ] flex flex-row flex-wrap border-b border-neutral-100 dark:border-neutral-700"> |
|||
<div |
|||
className={`py-1.5 px-4 flex items-center rounded-full font-medium text-xs cursor-pointer mr-2 my-1 sm:mr-3 ${ |
|||
dropOffLocationType === "roundTrip" |
|||
? "bg-black shadow-black/10 shadow-lg text-white" |
|||
: "border border-neutral-300 dark:border-neutral-700" |
|||
}`}
|
|||
onClick={(e) => setDropOffLocationType("roundTrip")} |
|||
> |
|||
Round-trip |
|||
</div> |
|||
<div |
|||
className={`py-1.5 px-4 flex items-center rounded-full font-medium text-xs cursor-pointer mr-2 my-1 sm:mr-3 ${ |
|||
dropOffLocationType === "oneWay" |
|||
? "bg-black text-white shadow-black/10 shadow-lg" |
|||
: "border border-neutral-300 dark:border-neutral-700" |
|||
}`}
|
|||
onClick={(e) => setDropOffLocationType("oneWay")} |
|||
> |
|||
One-way |
|||
</div> |
|||
|
|||
<div className="self-center border-r border-slate-200 dark:border-slate-700 h-8 mr-2 my-1 sm:mr-3"></div> |
|||
|
|||
<div className="mr-2 my-1 sm:mr-3 border border-neutral-300 dark:border-neutral-700 rounded-full"> |
|||
{renderSelectClass()} |
|||
</div> |
|||
<div className="my-1 border border-neutral-300 dark:border-neutral-700 rounded-full"> |
|||
{renderGuest()} |
|||
</div> |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
const renderForm = () => { |
|||
return ( |
|||
<form className="w-full relative mt-8 rounded-[40px] xl:rounded-[49px] rounded-t-2xl xl:rounded-t-3xl shadow-xl dark:shadow-2xl bg-white dark:bg-neutral-800"> |
|||
{renderRadioBtn()} |
|||
<div className="flex flex-1 rounded-full"> |
|||
<LocationInput |
|||
placeHolder="Flying from" |
|||
desc="Where do you want to fly from?" |
|||
className="flex-1" |
|||
/> |
|||
<div className="self-center border-r border-slate-200 dark:border-slate-700 h-8"></div> |
|||
<LocationInput |
|||
placeHolder="Flying to" |
|||
desc="Where you want to fly to?" |
|||
className="flex-1" |
|||
divHideVerticalLineClass=" -inset-x-0.5" |
|||
/> |
|||
<div className="self-center border-r border-slate-200 dark:border-slate-700 h-8"></div> |
|||
<FlightDateRangeInput |
|||
selectsRange={dropOffLocationType !== "oneWay"} |
|||
className="flex-1" |
|||
/> |
|||
</div> |
|||
</form> |
|||
); |
|||
}; |
|||
|
|||
return renderForm(); |
|||
}; |
|||
|
|||
export default FlightSearchForm; |
Write
Preview
Loading…
Cancel
Save
Reference in new issue