Browse Source

🚀 Implemented flight class selection

💼 Added guest count input fields
🗺️ Improved location inputs
📅 Enhanced date range selection
🔧 Minor code refactor and cleanup
main
John Doe 1 year ago
parent
commit
70e75aa6fc
  1. 246
      src/app/(client-components)/(HeroSearchForm)/(flight-search-form)/FlightSearchForm.tsx

246
src/app/(client-components)/(HeroSearchForm)/(flight-search-form)/FlightSearchForm.tsx

@ -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;
Loading…
Cancel
Save