sina_sajjadi
2 months ago
11 changed files with 130 additions and 1101 deletions
-
131src/app/(account-pages)/account/page.tsx
-
17src/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