Browse Source

build bugs fixed

main
sina_sajjadi 4 days ago
parent
commit
03a018a551
  1. 143
      src/app/(account-pages)/account/page.tsx
  2. 19
      src/app/(client-components)/(Header)/MainNav1.tsx
  3. 105
      src/app/(flight-listings)/SectionGridFilterCard.tsx
  4. 858
      src/app/(flight-listings)/TabFilters.tsx
  5. 47
      src/app/(flight-listings)/listing-flights/page.tsx
  6. 4
      src/app/forgot-password/page.tsx
  7. 4
      src/app/login/page.tsx
  8. 4
      src/app/signup/methodes/page.tsx
  9. 4
      src/app/signup/otp-code/page.tsx
  10. 4
      src/app/signup/page.tsx
  11. 39
      src/components/contexts/userContext.tsx

143
src/app/(account-pages)/account/page.tsx

@ -1,5 +1,5 @@
"use client";
import React, { useContext, useState } from "react";
import React, { useState, ChangeEvent, FC } from "react";
import Label from "@/components/Label";
import Avatar from "@/shared/Avatar";
import ButtonPrimary from "@/shared/ButtonPrimary";
@ -7,69 +7,91 @@ import Input from "@/shared/Input";
import ButtonSecondary from "@/shared/ButtonSecondary";
import axiosInstance from "@/components/api/axios";
import { useRouter } from "next/navigation";
import { user as UserContext } from "@/components/contexts/userContext";
import { useUserContext } from "@/components/contexts/userContext";
import getImageURL from "@/components/api/getImageURL";
export interface AccountPageProps {}
const AccountPage = () => {
interface User {
fullname: string;
email: string;
phone_number: string;
avatar: string;
token: string;
}
interface LoadingState {
delete?: boolean;
change?: boolean;
}
interface APIResponse {
data: {
avatar: string;
email: string;
fullname: string;
phone_number: string;
};
}
const AccountPage: FC<AccountPageProps> = () => {
const router = useRouter();
const User = JSON.parse(localStorage.getItem("user"));
let user = JSON.parse(localStorage.getItem("user"));
const storedUser = localStorage.getItem("user");
let user: User | null = storedUser ? JSON.parse(storedUser) : null;
if (!user) {
return router.replace("/");
router.replace("/");
return null; // Prevent rendering if no user data is found
}
const { setStatus } = useContext(UserContext);
const [name, setName] = useState(user.fullname || "");
const [email, setEmail] = useState(user.email || "");
const [number, setNumber] = useState(user.phone_number || "");
const [password, setPassword] = useState("");
const { setStatus } = useUserContext();
const [name, setName] = useState<string>(user.fullname || "");
const [email, setEmail] = useState<string>(user.email || "");
const [number, setNumber] = useState<string>(user.phone_number || "");
const [password, setPassword] = useState<string>("");
const [image, setImage] = useState<File | null>(null);
const [imageURL, setImageURL] = useState<string | null>(null);
const [error, setError] = useState("");
const [loading, setLoading] = useState({});
const [error, setError] = useState<string>("");
const [loading, setLoading] = useState<LoadingState>({});
const deleteHandler = async () => {
const deleteHandler = async (): Promise<void> => {
setError("");
setLoading({delete : true})
setLoading({ delete: true });
try {
const response = await axiosInstance.delete(
`/api/account/profile/delete/`,
{
headers: {
Authorization: `token ${user.token}`,
},
}
);
const response = await axiosInstance.delete(`/api/account/profile/delete/`, {
headers: {
Authorization: `token ${user?.token}`,
},
});
if (response.status === 204) {
localStorage.removeItem("user");
setStatus(false);
router.replace("/");
} else {
setError("Something went wrong");
}
} catch (error) {
setError(error.message);
} finally{
setLoading({delete : false})
} catch (error: unknown) {
if (error instanceof Error) {
setError(error.message);
} else {
setError("An unknown error occurred");
}
} finally {
setLoading({ delete: false });
}
};
const signOutHandler = () => {
const signOutHandler = (): void => {
localStorage.removeItem("user");
setStatus(false);
router.replace("/");
};
const changeHandler = async () => {
const changeHandler = async (): Promise<void> => {
setError("");
setLoading({change : true})
setLoading({ change: true });
const formData = new FormData();
formData.append("fullname", name);
@ -80,7 +102,7 @@ const AccountPage = () => {
}
try {
const response = await axiosInstance.put(
const response = await axiosInstance.put<APIResponse>(
`/api/account/profile/update/`,
formData,
{
@ -91,36 +113,34 @@ const AccountPage = () => {
}
);
if (response.status === 200) {
console.log(response);
user.avatar = response.data.avatar;
user.email = response.data.email;
user.fullname = response.data.fullname;
user.phone_number = response.data.phone_number;
user = {
...user,
avatar: response.data.avatar,
email: response.data.email,
fullname: response.data.fullname,
phone_number: response.data.phone_number,
};
localStorage.setItem("user", JSON.stringify(user));
} else {
setError("Something went wrong");
}
} catch (error) {
setError(error.message);
} finally{
setLoading({change : false})
} catch (error: unknown) {
if (error instanceof Error) {
setError(error.message);
} else {
setError("An unknown error occurred");
}
} finally {
setLoading({ change: false });
}
};
const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
const handleFileChange = async (e: ChangeEvent<HTMLInputElement>): Promise<void> => {
const file = e.target.files?.[0];
if (file) {
const uploadedFile = await getImageURL(file);
setImageURL(uploadedFile.url);
}
setImage(file);
};
@ -132,9 +152,7 @@ const AccountPage = () => {
<div className="flex-shrink-0 flex items-start">
<div className="relative rounded-full overflow-hidden flex">
<Avatar
imgUrl={
imageURL || (image ? URL.createObjectURL(image) : User.avatar)
}
imgUrl={imageURL || (image ? URL.createObjectURL(image) : user.avatar)}
sizeClass="w-32 h-32"
/>
<div className="absolute inset-0 bg-black bg-opacity-60 flex flex-col items-center justify-center text-neutral-50 cursor-pointer">
@ -199,17 +217,16 @@ const AccountPage = () => {
className="mt-1.5"
/>
</div>
{error && <p className=" text-red-500 text-xs">{error}</p>}
<div className=" flex flex-col pt-2 sm:flex-row ">
<ButtonPrimary className="mt-8" loading={loading.change} onClick={changeHandler}>
{error && <p className="text-red-500 text-xs">{error}</p>}
<div className="flex flex-col pt-2 sm:flex-row">
<ButtonPrimary className="mt-8" loading={loading.change} onClick={changeHandler}>
Update info
</ButtonPrimary>
<ButtonPrimary className="mt-8 sm:ml-8 " onClick={signOutHandler}>
{" "}
<ButtonPrimary className="mt-8 sm:ml-8" onClick={signOutHandler}>
Sign out
</ButtonPrimary>
<ButtonSecondary
loading={loading.delete}
loading={loading.delete}
onClick={deleteHandler}
className="opacity-60 mt-8 hover:bg-red-500 hover:text-white hover:opacity-100 sm:ml-8"
>

19
src/app/(client-components)/(Header)/MainNav1.tsx

@ -11,21 +11,22 @@ import HeroSearchForm2MobileFactory from "../(HeroSearchForm2Mobile)/HeroSearchF
import { MdOutlineLanguage } from "react-icons/md";
import Avatar from "@/shared/Avatar";
import Link from "next/link";
import { user } from "@/components/contexts/userContext";
import { useUserContext } from "@/components/contexts/userContext";
export interface MainNav1Props {
className?: string;
}
const MainNav1: FC<MainNav1Props> = ({ className = "" }) => {
const { status, setStatus } = useContext(user);
const { status, setStatus } =useUserContext();
const [userData , setUserData] =useState({})
useEffect(()=>{
setUserData(JSON.parse(localStorage.getItem("user")))
userData? setStatus(true) : setStatus(false)
const User = JSON.parse(localStorage.getItem("user"))
useEffect(()=>{
User? setStatus(true) : setStatus(false)
} , [])
} , [status])
console.log(status);
return (
<div className={`nc-MainNav1 relative z-10 ${className}`}>
@ -51,7 +52,7 @@ useEffect(()=>{
<div className="px-1" />
{status ? (<Link href={"/account"}>
<Avatar
imgUrl={User.avatar}
imgUrl={userData?.avatar}
sizeClass="w-10 h-10"
/>
</Link>

105
src/app/(flight-listings)/SectionGridFilterCard.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;

858
src/app/(flight-listings)/TabFilters.tsx

@ -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"
>
&#8203;
</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;

47
src/app/(flight-listings)/listing-flights/page.tsx

@ -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;

4
src/app/forgot-password/page.tsx

@ -9,7 +9,7 @@ import ButtonPrimary from "@/shared/ButtonPrimary";
import Image from "next/image";
import Link from "next/link";
import axiosInstance from "@/components/api/axios";
import { user } from "@/components/contexts/userContext";
import { useUserContext } from "@/components/contexts/userContext";
import useFormValidation from "@/hooks/FormValidation";
import { useRouter } from "next/navigation";
@ -19,7 +19,7 @@ const PageSignUp: FC<PageSignUpProps> = ({}) => {
const router = useRouter()
const { setForm , setMethod } = useContext(user);
const { setForm , setMethod } = useUserContext();
const [name, setName] = useState('');
const [countryCode, setCountryCode] = useState('');

4
src/app/login/page.tsx

@ -8,7 +8,7 @@ import Image from "next/image";
import Link from "next/link";
import axiosInstance from "@/components/api/axios";
import { useRouter } from "next/navigation";
import { user as UserContext } from "@/components/contexts/userContext";
import { useUserContext } from "@/components/contexts/userContext";
export interface PageLoginProps {}
const PageLogin: FC<PageLoginProps> = ({}) => {
@ -18,7 +18,7 @@ const PageLogin: FC<PageLoginProps> = ({}) => {
if (user) {
return router.replace("/")
}
const { setStatus } = useContext(UserContext);
const { setStatus } = useUserContext();
const [phoneNumber, setPhoneNumber] = useState("");
const [password, setPassword] = useState("");

4
src/app/signup/methodes/page.tsx

@ -1,7 +1,7 @@
"use client";
import axiosInstance from "@/components/api/axios";
import { user } from "@/components/contexts/userContext";
import { useUserContext } from "@/components/contexts/userContext";
import ButtonPrimary from "@/shared/ButtonPrimary";
import { useRouter } from "next/navigation";
import { useContext, useState } from "react";
@ -14,7 +14,7 @@ function SelectMethods() {
if (User) {
return router.replace("/");
}
const { method, form } = useContext(user);
const { method, form } = useUserContext();
const [selectedMethod, setSelectedMethod] = useState("");
const [error, setError] = useState("");
const [loading, setLoading] = useState("");

4
src/app/signup/otp-code/page.tsx

@ -3,7 +3,7 @@
import React, { FC, useContext, useState, useEffect, useRef } from "react";
import ButtonPrimary from "@/shared/ButtonPrimary";
import axiosInstance from "@/components/api/axios";
import { user as userContext } from "@/components/contexts/userContext";
import { useUserContext } from "@/components/contexts/userContext";
import useFormValidation from "@/hooks/FormValidation";
import { useRouter } from "next/navigation";
@ -12,7 +12,7 @@ export interface PageSignUpProps {}
const PageSignUp: FC<PageSignUpProps> = () => {
const router = useRouter();
const user = JSON.parse(localStorage.getItem("user"));
const { form, setMethod, setStatus } = useContext(userContext);
const { form, setMethod, setStatus } = useUserContext();
const [otp, setOtp] = useState(["", "", "", "", ""]);

4
src/app/signup/page.tsx

@ -5,7 +5,7 @@ import Input from "@/shared/Input";
import ButtonPrimary from "@/shared/ButtonPrimary";
import Link from "next/link";
import axiosInstance from "@/components/api/axios";
import { user as UserContext } from "@/components/contexts/userContext";
import { useUserContext } from "@/components/contexts/userContext";
import useFormValidation from "@/hooks/FormValidation";
import { useRouter } from "next/navigation";
@ -20,7 +20,7 @@ const PageSignUp: FC<PageSignUpProps> = () => {
return null; // Avoid rendering the component if the user is already logged in
}
const { setForm, setMethod } = useContext(UserContext);
const { setForm, setMethod } = useUserContext();
const [name, setName] = useState("");
const [countryCode, setCountryCode] = useState("");

39
src/components/contexts/userContext.tsx

@ -1,16 +1,29 @@
"use client";
import axiosInstance from "../api/axios";
import React, { createContext, useEffect, useState } from "react";
export const user = createContext();
import React, { createContext, useContext, useState, ReactNode } from "react";
export const UserProvider = ({ children }) => {
const [status, setStatus] = useState(false);
const [form, setForm] = useState({});
const [method, setMethod] = useState([]);
type UserContextType = {
status: boolean;
setStatus: (status: boolean) => void;
form: Record<string, any>;
setForm: (form: Record<string, any>) => void;
method: any[];
setMethod: (method: any[]) => void;
};
const UserContext = createContext<UserContextType | undefined>(undefined);
type UserProviderProps = {
children: ReactNode;
};
export const UserProvider: React.FC<UserProviderProps> = ({ children }) => {
const [status, setStatus] = useState<boolean>(false);
const [form, setForm] = useState<Record<string, any>>({});
const [method, setMethod] = useState<any[]>([]);
return (
<user.Provider
<UserContext.Provider
value={{
status,
setStatus,
@ -21,6 +34,14 @@ export const UserProvider = ({ children }) => {
}}
>
{children}
</user.Provider>
</UserContext.Provider>
);
};
export const useUserContext = () => {
const context = useContext(UserContext);
if (!context) {
throw new Error("useUserContext must be used within a UserProvider");
}
return context;
};
Loading…
Cancel
Save