sina_sajjadi
2 months ago
11 changed files with 130 additions and 1101 deletions
-
143src/app/(account-pages)/account/page.tsx
-
19src/app/(client-components)/(Header)/MainNav1.tsx
-
105src/app/(flight-listings)/SectionGridFilterCard.tsx
-
858src/app/(flight-listings)/TabFilters.tsx
-
47src/app/(flight-listings)/listing-flights/page.tsx
-
4src/app/forgot-password/page.tsx
-
4src/app/login/page.tsx
-
4src/app/signup/methodes/page.tsx
-
4src/app/signup/otp-code/page.tsx
-
4src/app/signup/page.tsx
-
39src/components/contexts/userContext.tsx
@ -1,105 +0,0 @@ |
|||
import React, { FC } from "react"; |
|||
import TabFilters from "./TabFilters"; |
|||
import Heading2 from "@/shared/Heading2"; |
|||
import FlightCard, { FlightCardProps } from "@/components/FlightCard"; |
|||
import ButtonPrimary from "@/shared/ButtonPrimary"; |
|||
|
|||
export interface SectionGridFilterCardProps { |
|||
className?: string; |
|||
} |
|||
|
|||
const DEMO_DATA: FlightCardProps["data"][] = [ |
|||
{ |
|||
id: "1", |
|||
price: "$4,100", |
|||
airlines: { |
|||
logo: "https://www.gstatic.com/flights/airline_logos/70px/KE.png", |
|||
name: "Korean Air", |
|||
}, |
|||
}, |
|||
{ |
|||
id: "2", |
|||
price: "$3,380", |
|||
airlines: { |
|||
logo: "https://www.gstatic.com/flights/airline_logos/70px/SQ.png", |
|||
name: "Singapore Airlines", |
|||
}, |
|||
}, |
|||
{ |
|||
id: "3", |
|||
price: "$2,380", |
|||
airlines: { |
|||
logo: "https://www.gstatic.com/flights/airline_logos/70px/multi.png", |
|||
name: "Philippine Airlines", |
|||
}, |
|||
}, |
|||
{ |
|||
id: "1", |
|||
price: "$4,100", |
|||
airlines: { |
|||
logo: "https://www.gstatic.com/flights/airline_logos/70px/KE.png", |
|||
name: "Korean Air", |
|||
}, |
|||
}, |
|||
{ |
|||
id: "2", |
|||
price: "$3,380", |
|||
airlines: { |
|||
logo: "https://www.gstatic.com/flights/airline_logos/70px/SQ.png", |
|||
name: "Singapore Airlines", |
|||
}, |
|||
}, |
|||
{ |
|||
id: "1", |
|||
price: "$4,100", |
|||
airlines: { |
|||
logo: "https://www.gstatic.com/flights/airline_logos/70px/KE.png", |
|||
name: "Korean Air", |
|||
}, |
|||
}, |
|||
{ |
|||
id: "2", |
|||
price: "$3,380", |
|||
airlines: { |
|||
logo: "https://www.gstatic.com/flights/airline_logos/70px/SQ.png", |
|||
name: "Singapore Airlines", |
|||
}, |
|||
}, |
|||
]; |
|||
|
|||
const SectionGridFilterCard: FC<SectionGridFilterCardProps> = ({ |
|||
className = "", |
|||
}) => { |
|||
return ( |
|||
<div |
|||
className={`nc-SectionGridFilterCard ${className}`} |
|||
data-nc-id="SectionGridFilterCard" |
|||
> |
|||
<Heading2 |
|||
heading="Singapore - Tokyo" |
|||
subHeading={ |
|||
<span className="block text-neutral-500 dark:text-neutral-400 mt-3"> |
|||
22 flights |
|||
<span className="mx-2">·</span> |
|||
round trip |
|||
<span className="mx-2">·</span>2 Guests |
|||
</span> |
|||
} |
|||
/> |
|||
<div className="mb-8 lg:mb-11"> |
|||
<TabFilters /> |
|||
</div> |
|||
<div className="lg:p-10 lg:bg-neutral-50 lg:dark:bg-black/20 grid grid-cols-1 gap-6 rounded-3xl"> |
|||
{DEMO_DATA.map((item, index) => ( |
|||
<FlightCard key={index} data={item} /> |
|||
))} |
|||
|
|||
<div className="flex mt-12 justify-center items-center"> |
|||
<ButtonPrimary loading>Show more</ButtonPrimary> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
export default SectionGridFilterCard; |
@ -1,858 +0,0 @@ |
|||
"use client"; |
|||
|
|||
import React, { Fragment, useState } from "react"; |
|||
import { Dialog, Popover, Tab, Transition } from "@headlessui/react"; |
|||
import ButtonPrimary from "@/shared/ButtonPrimary"; |
|||
import ButtonThird from "@/shared/ButtonThird"; |
|||
import ButtonClose from "@/shared/ButtonClose"; |
|||
import Checkbox from "@/shared/Checkbox"; |
|||
import convertNumbThousand from "@/utils/convertNumbThousand"; |
|||
import Slider from "rc-slider"; |
|||
import { XMarkIcon } from "@heroicons/react/24/outline"; |
|||
|
|||
// DEMO DATA
|
|||
const typeOfAirlines = [ |
|||
{ |
|||
name: "Star Alliance", |
|||
}, |
|||
{ |
|||
name: "Air China", |
|||
}, |
|||
{ |
|||
name: "Air India", |
|||
}, |
|||
{ |
|||
name: "Air New Zealand", |
|||
}, |
|||
{ |
|||
name: "Asiana", |
|||
}, |
|||
{ |
|||
name: "Bangkok Airways", |
|||
}, |
|||
]; |
|||
const stopPoints = [ |
|||
{ |
|||
name: "Nonstop", |
|||
}, |
|||
{ |
|||
name: "Up to 1 stops", |
|||
}, |
|||
{ |
|||
name: "Up to 2 stops", |
|||
}, |
|||
{ |
|||
name: "Any number of stops", |
|||
}, |
|||
]; |
|||
|
|||
//
|
|||
const TabFilters = () => { |
|||
const [isOpenMoreFilter, setisOpenMoreFilter] = useState(false); |
|||
//
|
|||
const [isOnSale, setIsOnSale] = useState(true); |
|||
const [rangePrices, setRangePrices] = useState([100, 5000]); |
|||
const [tripTimes, setTripTimes] = useState(10); |
|||
const [stopPontsStates, setStopPontsStates] = useState<string[]>([]); |
|||
const [airlinesStates, setAirlinesStates] = useState<string[]>([]); |
|||
|
|||
//
|
|||
let [catTimes, setCatTimes] = useState({ |
|||
"Take Off": { |
|||
Departure: [0, 24], |
|||
Arrival: [0, 24], |
|||
}, |
|||
Landing: { |
|||
Departure: [0, 24], |
|||
Arrival: [0, 24], |
|||
}, |
|||
}); |
|||
|
|||
//
|
|||
const closeModalMoreFilter = () => setisOpenMoreFilter(false); |
|||
const openModalMoreFilter = () => setisOpenMoreFilter(true); |
|||
|
|||
//
|
|||
const handleChangeStopPoint = (checked: boolean, name: string) => { |
|||
checked |
|||
? setStopPontsStates([...stopPontsStates, name]) |
|||
: setStopPontsStates(stopPontsStates.filter((i) => i !== name)); |
|||
}; |
|||
|
|||
const handleChangeAirlines = (checked: boolean, name: string) => { |
|||
checked |
|||
? setAirlinesStates([...airlinesStates, name]) |
|||
: setAirlinesStates(airlinesStates.filter((i) => i !== name)); |
|||
}; |
|||
|
|||
//
|
|||
|
|||
const renderXClear = () => { |
|||
return ( |
|||
<span className="w-4 h-4 rounded-full bg-primary-500 text-white flex items-center justify-center ml-3 cursor-pointer"> |
|||
<XMarkIcon className="h-3 w-3" /> |
|||
</span> |
|||
); |
|||
}; |
|||
|
|||
const renderTabsTimeFlightTab = () => { |
|||
return ( |
|||
<div> |
|||
<Tab.Group> |
|||
<Tab.List className="flex p-1 space-x-1 bg-primary-900/10 rounded-xl"> |
|||
{Object.keys(catTimes).map((category) => ( |
|||
<Tab |
|||
key={category} |
|||
className={({ selected }) => |
|||
`w-full py-2.5 text-sm leading-5 font-medium text-primary-700 dark:text-primary-400 rounded-lg focus:outline-none focus:ring-2 ring-offset-2 ring-offset-blue-400 ring-white ring-opacity-60 ${ |
|||
selected |
|||
? "bg-white dark:bg-neutral-800 shadow" |
|||
: " hover:bg-white/[0.15] dark:hover:bg-neutral-800" |
|||
}`
|
|||
} |
|||
> |
|||
{category} |
|||
</Tab> |
|||
))} |
|||
</Tab.List> |
|||
<Tab.Panels className="mt-2"> |
|||
{Object.values(catTimes).map((posts, idx) => { |
|||
return ( |
|||
<Tab.Panel |
|||
key={idx} |
|||
className={ |
|||
"bg-neutral-50 dark:bg-neutral-900 rounded-xl p-3 space-y-8 focus:outline-none focus:ring-2 ring-offset-2 ring-offset-blue-400 ring-white ring-opacity-60" |
|||
} |
|||
> |
|||
<span className=" text-neutral-6000 dark:text-neutral-300 text-sm"> |
|||
{idx ? " Tokyo to Singapore" : " Singapore to Tokyo"} |
|||
</span> |
|||
<div></div> |
|||
<div className="space-y-3"> |
|||
<div className="flex space-x-2"> |
|||
<i className="text-lg las la-plane-departure"></i> |
|||
<span className="text-xs">Departure time:</span> |
|||
<span className="text-xs text-primary-500 dark:text-primary-400"> |
|||
{posts.Departure[0]}:00 - {posts.Departure[1]} |
|||
:00 |
|||
</span> |
|||
</div> |
|||
<Slider |
|||
range |
|||
min={0} |
|||
max={24} |
|||
defaultValue={posts.Departure} |
|||
onChange={(val) => |
|||
setCatTimes((catTimes) => |
|||
!idx |
|||
? { |
|||
...catTimes, |
|||
"Take Off": { |
|||
...posts, |
|||
Departure: val as [number, number], |
|||
}, |
|||
} |
|||
: { |
|||
...catTimes, |
|||
Landing: { |
|||
...posts, |
|||
Departure: val as [number, number], |
|||
}, |
|||
} |
|||
) |
|||
} |
|||
allowCross={false} |
|||
/> |
|||
</div> |
|||
<div className="space-y-3"> |
|||
<div className="flex space-x-2"> |
|||
<i className="text-lg las la-plane-arrival"></i> |
|||
<span className="text-xs">Arrival time:</span> |
|||
<span className="text-xs text-primary-500 dark:text-primary-400"> |
|||
{posts.Arrival[0]}:00 - {posts.Arrival[1]}:00 |
|||
</span> |
|||
</div> |
|||
<Slider |
|||
range |
|||
min={0} |
|||
max={24} |
|||
defaultValue={posts.Arrival} |
|||
onChange={(val) => |
|||
setCatTimes((catTimes) => |
|||
!idx |
|||
? { |
|||
...catTimes, |
|||
"Take Off": { |
|||
...posts, |
|||
Arrival: val as [number, number], |
|||
}, |
|||
} |
|||
: { |
|||
...catTimes, |
|||
Landing: { |
|||
...posts, |
|||
Arrival: val as [number, number], |
|||
}, |
|||
} |
|||
) |
|||
} |
|||
allowCross={false} |
|||
/> |
|||
</div> |
|||
</Tab.Panel> |
|||
); |
|||
})} |
|||
</Tab.Panels> |
|||
</Tab.Group> |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
const renderTabsTypeOfAirlines = () => { |
|||
return ( |
|||
<Popover className="relative"> |
|||
{({ open, close }) => ( |
|||
<> |
|||
<Popover.Button |
|||
className={`flex items-center justify-center px-4 py-2 text-sm rounded-full border border-neutral-300 dark:border-neutral-700 focus:outline-none
|
|||
${open ? "!border-primary-500 " : ""} |
|||
${ |
|||
!!airlinesStates.length |
|||
? "!border-primary-500 bg-primary-50" |
|||
: "" |
|||
} |
|||
`}
|
|||
> |
|||
<span>Airlines</span> |
|||
{!airlinesStates.length ? ( |
|||
<i className="las la-angle-down ml-2"></i> |
|||
) : ( |
|||
<span onClick={() => setAirlinesStates([])}> |
|||
{renderXClear()} |
|||
</span> |
|||
)} |
|||
</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-10 w-screen max-w-sm px-4 mt-3 left-0 sm:px-0 lg:max-w-md"> |
|||
<div className="overflow-hidden rounded-2xl shadow-xl bg-white dark:bg-neutral-900 border border-neutral-200 dark:border-neutral-700"> |
|||
<div className="relative flex flex-col px-5 py-6 space-y-5"> |
|||
<Checkbox |
|||
name="All Airlines" |
|||
label="All Airlines" |
|||
defaultChecked={airlinesStates.includes("All Airlines")} |
|||
onChange={(checked) => |
|||
handleChangeAirlines(checked, "All Airlines") |
|||
} |
|||
/> |
|||
<hr /> |
|||
{typeOfAirlines.map((item) => ( |
|||
<div key={item.name} className=""> |
|||
<Checkbox |
|||
name={item.name} |
|||
label={item.name} |
|||
defaultChecked={airlinesStates.includes(item.name)} |
|||
onChange={(checked) => |
|||
handleChangeAirlines(checked, item.name) |
|||
} |
|||
/> |
|||
</div> |
|||
))} |
|||
</div> |
|||
<div className="p-5 bg-neutral-50 dark:bg-neutral-900 dark:border-t dark:border-neutral-800 flex items-center justify-between"> |
|||
<ButtonThird |
|||
onClick={() => { |
|||
close(); |
|||
setAirlinesStates([]); |
|||
}} |
|||
sizeClass="px-4 py-2 sm:px-5" |
|||
> |
|||
Clear |
|||
</ButtonThird> |
|||
<ButtonPrimary |
|||
onClick={close} |
|||
sizeClass="px-4 py-2 sm:px-5" |
|||
> |
|||
Apply |
|||
</ButtonPrimary> |
|||
</div> |
|||
</div> |
|||
</Popover.Panel> |
|||
</Transition> |
|||
</> |
|||
)} |
|||
</Popover> |
|||
); |
|||
}; |
|||
|
|||
const renderTabsStopPoints = () => { |
|||
return ( |
|||
<Popover className="relative"> |
|||
{({ open, close }) => ( |
|||
<> |
|||
<Popover.Button |
|||
className={`flex items-center justify-center px-4 py-2 text-sm rounded-full border border-neutral-300 dark:border-neutral-700 focus:outline-none
|
|||
${open ? "!border-primary-500 " : ""} |
|||
${ |
|||
!!stopPontsStates.length |
|||
? "!border-primary-500 bg-primary-50" |
|||
: "" |
|||
} |
|||
`}
|
|||
> |
|||
<span>Stop points</span> |
|||
{!stopPontsStates.length ? ( |
|||
<i className="las la-angle-down ml-2"></i> |
|||
) : ( |
|||
<span onClick={() => setStopPontsStates([])}> |
|||
{renderXClear()} |
|||
</span> |
|||
)} |
|||
</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-10 w-screen max-w-sm px-4 mt-3 left-0 sm:px-0 lg:max-w-md"> |
|||
<div className="overflow-hidden rounded-2xl shadow-xl bg-white dark:bg-neutral-900 border border-neutral-200 dark:border-neutral-700"> |
|||
<div className="relative flex flex-col px-5 py-6 space-y-5"> |
|||
{stopPoints.map((item) => ( |
|||
<div key={item.name} className=""> |
|||
<Checkbox |
|||
name={item.name} |
|||
label={item.name} |
|||
defaultChecked={stopPontsStates.includes(item.name)} |
|||
onChange={(checked) => |
|||
handleChangeStopPoint(checked, item.name) |
|||
} |
|||
/> |
|||
</div> |
|||
))} |
|||
</div> |
|||
<div className="p-5 bg-neutral-50 dark:bg-neutral-900 dark:border-t dark:border-neutral-800 flex items-center justify-between"> |
|||
<ButtonThird |
|||
onClick={() => { |
|||
close(); |
|||
setStopPontsStates([]); |
|||
}} |
|||
sizeClass="px-4 py-2 sm:px-5" |
|||
> |
|||
Clear |
|||
</ButtonThird> |
|||
<ButtonPrimary |
|||
onClick={close} |
|||
sizeClass="px-4 py-2 sm:px-5" |
|||
> |
|||
Apply |
|||
</ButtonPrimary> |
|||
</div> |
|||
</div> |
|||
</Popover.Panel> |
|||
</Transition> |
|||
</> |
|||
)} |
|||
</Popover> |
|||
); |
|||
}; |
|||
|
|||
const renderTabsTimeFlight = () => { |
|||
return ( |
|||
<Popover className="relative"> |
|||
{({ open, close }) => ( |
|||
<> |
|||
<Popover.Button |
|||
className={`flex items-center justify-center px-4 py-2 text-sm rounded-full border border-neutral-300 dark:border-neutral-700 focus:outline-none ${ |
|||
open ? "!border-primary-500 " : "" |
|||
}`}
|
|||
> |
|||
<span>Flight time</span> |
|||
<i className="las la-angle-down ml-2"></i> |
|||
</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-10 w-screen max-w-sm px-4 mt-3 left-0 sm:px-0 lg:max-w-md"> |
|||
<div className="overflow-hidden rounded-2xl shadow-xl bg-white dark:bg-neutral-900 border border-neutral-200 dark:border-neutral-700"> |
|||
<div className="relative flex flex-col px-5 py-6 space-y-5"> |
|||
{renderTabsTimeFlightTab()} |
|||
</div> |
|||
<div className="p-5 bg-neutral-50 dark:bg-neutral-900 dark:border-t dark:border-neutral-800 flex items-center justify-between"> |
|||
<ButtonThird onClick={close} sizeClass="px-4 py-2 sm:px-5"> |
|||
Clear |
|||
</ButtonThird> |
|||
<ButtonPrimary |
|||
onClick={close} |
|||
sizeClass="px-4 py-2 sm:px-5" |
|||
> |
|||
Apply |
|||
</ButtonPrimary> |
|||
</div> |
|||
</div> |
|||
</Popover.Panel> |
|||
</Transition> |
|||
</> |
|||
)} |
|||
</Popover> |
|||
); |
|||
}; |
|||
|
|||
const renderTabsTripTime = () => { |
|||
return ( |
|||
<Popover className="relative"> |
|||
{({ open, close }) => ( |
|||
<> |
|||
<Popover.Button |
|||
className={`flex items-center justify-center px-4 py-2 text-sm rounded-full border border-primary-500 bg-primary-50 text-primary-700 focus:outline-none `} |
|||
> |
|||
<span>less than {tripTimes} hours</span> |
|||
{renderXClear()} |
|||
</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-10 w-screen max-w-sm px-4 mt-3 left-0 sm:px-0 "> |
|||
<div className="overflow-hidden rounded-2xl shadow-xl bg-white dark:bg-neutral-900 border border-neutral-200 dark:border-neutral-700"> |
|||
<div className="relative flex flex-col px-5 py-6 space-y-8"> |
|||
<div className="space-y-5"> |
|||
<div className="font-medium"> |
|||
Trip time: |
|||
<span className="text-sm font-normal ml-1 text-primary-500">{` <${tripTimes} hours`}</span> |
|||
</div> |
|||
|
|||
<Slider |
|||
min={1} |
|||
max={72} |
|||
defaultValue={tripTimes} |
|||
onChange={(e) => setTripTimes(e as number)} |
|||
/> |
|||
</div> |
|||
</div> |
|||
<div className="p-5 bg-neutral-50 dark:bg-neutral-900 dark:border-t dark:border-neutral-800 flex items-center justify-between"> |
|||
<ButtonThird onClick={close} sizeClass="px-4 py-2 sm:px-5"> |
|||
Clear |
|||
</ButtonThird> |
|||
<ButtonPrimary |
|||
onClick={close} |
|||
sizeClass="px-4 py-2 sm:px-5" |
|||
> |
|||
Apply |
|||
</ButtonPrimary> |
|||
</div> |
|||
</div> |
|||
</Popover.Panel> |
|||
</Transition> |
|||
</> |
|||
)} |
|||
</Popover> |
|||
); |
|||
}; |
|||
|
|||
const renderTabsPriceRage = () => { |
|||
return ( |
|||
<Popover className="relative"> |
|||
{({ open, close }) => ( |
|||
<> |
|||
<Popover.Button |
|||
className={`flex items-center justify-center px-4 py-2 text-sm rounded-full border border-primary-500 bg-primary-50 text-primary-700 focus:outline-none `} |
|||
> |
|||
<span> |
|||
{`$${convertNumbThousand( |
|||
rangePrices[0] |
|||
)} - $${convertNumbThousand(rangePrices[1])}`}{" "}
|
|||
</span> |
|||
{renderXClear()} |
|||
</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-10 w-screen max-w-sm px-4 mt-3 left-0 sm:px-0 "> |
|||
<div className="overflow-hidden rounded-2xl shadow-xl bg-white dark:bg-neutral-900 border border-neutral-200 dark:border-neutral-700"> |
|||
<div className="relative flex flex-col px-5 py-6 space-y-8"> |
|||
<div className="space-y-5"> |
|||
<span className="font-medium">Price per person</span> |
|||
<Slider |
|||
range |
|||
min={100} |
|||
max={5000} |
|||
defaultValue={[rangePrices[0], rangePrices[1]]} |
|||
allowCross={false} |
|||
onChange={(e) => setRangePrices(e as number[])} |
|||
/> |
|||
</div> |
|||
|
|||
<div className="flex justify-between space-x-5"> |
|||
<div> |
|||
<label |
|||
htmlFor="minPrice" |
|||
className="block text-sm font-medium text-neutral-700 dark:text-neutral-300" |
|||
> |
|||
Min price |
|||
</label> |
|||
<div className="mt-1 relative rounded-md"> |
|||
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none"> |
|||
<span className="text-neutral-500 sm:text-sm"> |
|||
$ |
|||
</span> |
|||
</div> |
|||
<input |
|||
type="text" |
|||
name="minPrice" |
|||
disabled |
|||
id="minPrice" |
|||
className="focus:ring-indigo-500 focus:border-indigo-500 block w-full pl-7 pr-3 sm:text-sm border-neutral-200 rounded-full text-neutral-900" |
|||
value={rangePrices[0]} |
|||
/> |
|||
</div> |
|||
</div> |
|||
<div> |
|||
<label |
|||
htmlFor="maxPrice" |
|||
className="block text-sm font-medium text-neutral-700 dark:text-neutral-300" |
|||
> |
|||
Max price |
|||
</label> |
|||
<div className="mt-1 relative rounded-md"> |
|||
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none"> |
|||
<span className="text-neutral-500 sm:text-sm"> |
|||
$ |
|||
</span> |
|||
</div> |
|||
<input |
|||
type="text" |
|||
disabled |
|||
name="maxPrice" |
|||
id="maxPrice" |
|||
className="focus:ring-indigo-500 focus:border-indigo-500 block w-full pl-7 pr-3 sm:text-sm border-neutral-200 rounded-full text-neutral-900" |
|||
value={rangePrices[1]} |
|||
/> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div className="p-5 bg-neutral-50 dark:bg-neutral-900 dark:border-t dark:border-neutral-800 flex items-center justify-between"> |
|||
<ButtonThird onClick={close} sizeClass="px-4 py-2 sm:px-5"> |
|||
Clear |
|||
</ButtonThird> |
|||
<ButtonPrimary |
|||
onClick={close} |
|||
sizeClass="px-4 py-2 sm:px-5" |
|||
> |
|||
Apply |
|||
</ButtonPrimary> |
|||
</div> |
|||
</div> |
|||
</Popover.Panel> |
|||
</Transition> |
|||
</> |
|||
)} |
|||
</Popover> |
|||
); |
|||
}; |
|||
|
|||
const renderTabOnSale = () => { |
|||
return ( |
|||
<div |
|||
className={`flex items-center justify-center px-4 py-2 text-sm rounded-full border focus:outline-none cursor-pointer transition-all ${ |
|||
isOnSale |
|||
? "border-primary-500 bg-primary-50 text-primary-700" |
|||
: "border-neutral-300 dark:border-neutral-700" |
|||
}`}
|
|||
onClick={() => setIsOnSale(!isOnSale)} |
|||
> |
|||
<span>On sale</span> |
|||
{isOnSale && renderXClear()} |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
const renderMoreFilterItem = ( |
|||
data: { |
|||
name: string; |
|||
description?: string; |
|||
defaultChecked?: boolean; |
|||
}[] |
|||
) => { |
|||
const list1 = data.filter((_, i) => i < data.length / 2); |
|||
const list2 = data.filter((_, i) => i >= data.length / 2); |
|||
return ( |
|||
<div className="grid grid-cols-2 gap-8"> |
|||
<div className="flex flex-col space-y-5"> |
|||
{list1.map((item) => ( |
|||
<Checkbox |
|||
key={item.name} |
|||
name={item.name} |
|||
subLabel={item.description} |
|||
label={item.name} |
|||
defaultChecked={!!item.defaultChecked} |
|||
/> |
|||
))} |
|||
</div> |
|||
<div className="flex flex-col space-y-5"> |
|||
{list2.map((item) => ( |
|||
<Checkbox |
|||
key={item.name} |
|||
name={item.name} |
|||
subLabel={item.description} |
|||
label={item.name} |
|||
defaultChecked={!!item.defaultChecked} |
|||
/> |
|||
))} |
|||
</div> |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
// FOR RESPONSIVE MOBILE
|
|||
const renderTabMobileFilter = () => { |
|||
return ( |
|||
<div> |
|||
<div |
|||
className={`flex items-center justify-center px-4 py-2 text-sm rounded-full border border-primary-500 bg-primary-50 text-primary-700 focus:outline-none cursor-pointer`} |
|||
onClick={openModalMoreFilter} |
|||
> |
|||
<span> |
|||
<span className="hidden sm:inline">Flights</span> filters (3) |
|||
</span> |
|||
{renderXClear()} |
|||
</div> |
|||
|
|||
<Transition appear show={isOpenMoreFilter} as={Fragment}> |
|||
<Dialog |
|||
as="div" |
|||
className="fixed inset-0 z-50 overflow-y-auto" |
|||
onClose={closeModalMoreFilter} |
|||
> |
|||
<div className="min-h-screen text-center"> |
|||
<Transition.Child |
|||
as={Fragment} |
|||
enter="ease-out duration-300" |
|||
enterFrom="opacity-0" |
|||
enterTo="opacity-100" |
|||
leave="ease-in duration-200" |
|||
leaveFrom="opacity-100" |
|||
leaveTo="opacity-0" |
|||
> |
|||
<Dialog.Overlay className="fixed inset-0 bg-black bg-opacity-40 dark:bg-opacity-60" /> |
|||
</Transition.Child> |
|||
|
|||
{/* This element is to trick the browser into centering the modal contents. */} |
|||
<span |
|||
className="inline-block h-screen align-middle" |
|||
aria-hidden="true" |
|||
> |
|||
​ |
|||
</span> |
|||
<Transition.Child |
|||
className="inline-block py-8 px-2 h-screen w-full max-w-4xl" |
|||
enter="ease-out duration-300" |
|||
enterFrom="opacity-0 scale-95" |
|||
enterTo="opacity-100 scale-100" |
|||
leave="ease-in duration-200" |
|||
leaveFrom="opacity-100 scale-100" |
|||
leaveTo="opacity-0 scale-95" |
|||
> |
|||
<div className="inline-flex flex-col w-full max-w-4xl text-left align-middle transition-all transform overflow-hidden rounded-2xl bg-white dark:bg-neutral-900 dark:border dark:border-neutral-700 dark:text-neutral-100 shadow-xl h-full"> |
|||
<div className="relative flex-shrink-0 px-6 py-4 border-b border-neutral-200 dark:border-neutral-800 text-center"> |
|||
<Dialog.Title |
|||
as="h3" |
|||
className="text-lg font-medium leading-6 text-gray-900" |
|||
> |
|||
Flight filters |
|||
</Dialog.Title> |
|||
<span className="absolute left-3 top-3"> |
|||
<ButtonClose onClick={closeModalMoreFilter} /> |
|||
</span> |
|||
</div> |
|||
|
|||
<div className="flex-grow overflow-y-auto"> |
|||
<div className="px-4 md:px-10 divide-y divide-neutral-200 dark:divide-neutral-800"> |
|||
{/* --------- */} |
|||
{/* ---- */} |
|||
<div className="py-7"> |
|||
<h3 className="text-xl font-medium">Airlines</h3> |
|||
<div className="mt-6 relative "> |
|||
{renderMoreFilterItem(typeOfAirlines)} |
|||
</div> |
|||
</div> |
|||
{/* --------- */} |
|||
{/* ---- */} |
|||
<div className="py-7"> |
|||
<h3 className="text-xl font-medium">Stop points</h3> |
|||
<div className="mt-6 relative "> |
|||
{renderMoreFilterItem(stopPoints)} |
|||
</div> |
|||
</div> |
|||
|
|||
{/* --------- */} |
|||
{/* ---- */} |
|||
<div className="py-7"> |
|||
<h3 className="text-xl font-medium">Range Prices</h3> |
|||
<div className="mt-6 relative "> |
|||
<div className="relative flex flex-col space-y-8"> |
|||
<div className="space-y-5"> |
|||
<Slider |
|||
range |
|||
className="text-red-400" |
|||
min={0} |
|||
max={2000} |
|||
defaultValue={[0, 1000]} |
|||
allowCross={false} |
|||
onChange={(e) => setRangePrices(e as number[])} |
|||
/> |
|||
</div> |
|||
|
|||
<div className="flex justify-between space-x-5"> |
|||
<div> |
|||
<label |
|||
htmlFor="minPrice" |
|||
className="block text-sm font-medium text-neutral-700 dark:text-neutral-300" |
|||
> |
|||
Min price |
|||
</label> |
|||
<div className="mt-1 relative rounded-md"> |
|||
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none"> |
|||
<span className="text-neutral-500 sm:text-sm"> |
|||
$ |
|||
</span> |
|||
</div> |
|||
<input |
|||
type="text" |
|||
name="minPrice" |
|||
disabled |
|||
id="minPrice" |
|||
className="focus:ring-indigo-500 focus:border-indigo-500 block w-full pl-7 pr-3 sm:text-sm border-neutral-200 rounded-full text-neutral-900" |
|||
value={rangePrices[0]} |
|||
/> |
|||
</div> |
|||
</div> |
|||
<div> |
|||
<label |
|||
htmlFor="maxPrice" |
|||
className="block text-sm font-medium text-neutral-700 dark:text-neutral-300" |
|||
> |
|||
Max price |
|||
</label> |
|||
<div className="mt-1 relative rounded-md"> |
|||
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none"> |
|||
<span className="text-neutral-500 sm:text-sm"> |
|||
$ |
|||
</span> |
|||
</div> |
|||
<input |
|||
type="text" |
|||
disabled |
|||
name="maxPrice" |
|||
id="maxPrice" |
|||
className="focus:ring-indigo-500 focus:border-indigo-500 block w-full pl-7 pr-3 sm:text-sm border-neutral-200 rounded-full text-neutral-900" |
|||
value={rangePrices[1]} |
|||
/> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
{/* --------- */} |
|||
{/* ---- */} |
|||
<div className="py-7"> |
|||
<h3 className="text-xl font-medium"> |
|||
Strip times |
|||
<span className="text-sm font-normal ml-1 text-primary-500">{` <${tripTimes} hours`}</span> |
|||
</h3> |
|||
<div className="mt-6 relative "> |
|||
<Slider |
|||
min={1} |
|||
max={72} |
|||
defaultValue={tripTimes} |
|||
onChange={(e) => setTripTimes(e as number)} |
|||
/> |
|||
</div> |
|||
</div> |
|||
|
|||
{/* --------- */} |
|||
{/* ---- */} |
|||
<div className="py-7"> |
|||
<h3 className="text-xl font-medium">Flight times</h3> |
|||
<div className="relative flex flex-col py-5 space-y-5"> |
|||
{renderTabsTimeFlightTab()} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div className="p-4 sm:p-6 flex-shrink-0 bg-neutral-50 dark:bg-neutral-900 dark:border-t dark:border-neutral-800 flex items-center justify-between"> |
|||
<ButtonThird |
|||
onClick={closeModalMoreFilter} |
|||
sizeClass="px-4 py-2 sm:px-5" |
|||
> |
|||
Clear |
|||
</ButtonThird> |
|||
<ButtonPrimary |
|||
onClick={closeModalMoreFilter} |
|||
sizeClass="px-4 py-2 sm:px-5" |
|||
> |
|||
Apply |
|||
</ButtonPrimary> |
|||
</div> |
|||
</div> |
|||
</Transition.Child> |
|||
</div> |
|||
</Dialog> |
|||
</Transition> |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
return ( |
|||
<div className="flex lg:space-x-4"> |
|||
{/* FOR DESKTOP */} |
|||
<div className="hidden lg:flex space-x-4"> |
|||
{renderTabsTypeOfAirlines()} |
|||
{renderTabsTripTime()} |
|||
{renderTabsStopPoints()} |
|||
{renderTabsPriceRage()} |
|||
{renderTabsTimeFlight()} |
|||
{renderTabOnSale()} |
|||
</div> |
|||
|
|||
{/* FOR RESPONSIVE MOBILE */} |
|||
<div className="flex lg:hidden space-x-4"> |
|||
{renderTabMobileFilter()} |
|||
{renderTabOnSale()} |
|||
</div> |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
export default TabFilters; |
@ -1,47 +0,0 @@ |
|||
import SectionHeroArchivePage from "@/app/(server-components)/SectionHeroArchivePage"; |
|||
import BgGlassmorphism from "@/components/BgGlassmorphism"; |
|||
import SectionSliderNewCategories from "@/components/SectionSliderNewCategories"; |
|||
import SectionSubscribe2 from "@/components/SectionSubscribe2"; |
|||
import React, { FC } from "react"; |
|||
import SectionGridFilterCard from "../SectionGridFilterCard"; |
|||
|
|||
export interface ListingFlightsPageProps {} |
|||
|
|||
const ListingFlightsPage: FC<ListingFlightsPageProps> = ({}) => { |
|||
return ( |
|||
<div className={`nc-ListingFlightsPage relative overflow-hidden `}> |
|||
<BgGlassmorphism /> |
|||
|
|||
<div className="container relative"> |
|||
{/* SECTION HERO */} |
|||
<SectionHeroArchivePage |
|||
currentPage="Flights" |
|||
currentTab="Flights" |
|||
listingType={ |
|||
<> |
|||
<i className="text-2xl las la-plane-departure"></i> |
|||
<span className="ml-2.5">1599 flights</span> |
|||
</> |
|||
} |
|||
className="pt-10 pb-24 lg:pb-28 lg:pt-16 " |
|||
/> |
|||
|
|||
{/* SECTION */} |
|||
<SectionGridFilterCard className="pb-24 lg:pb-28" /> |
|||
|
|||
{/* SECTION 1 */} |
|||
<SectionSliderNewCategories |
|||
heading="Explore top destination ✈" |
|||
subHeading="Explore thousands of destinations around the world" |
|||
categoryCardType="card4" |
|||
itemPerRow={4} |
|||
/> |
|||
|
|||
{/* SECTION */} |
|||
<SectionSubscribe2 className="py-24 lg:py-28" /> |
|||
</div> |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
export default ListingFlightsPage; |
Write
Preview
Loading…
Cancel
Save
Reference in new issue