diff --git a/next.config.js b/next.config.js index 35d3ca8..95705ee 100644 --- a/next.config.js +++ b/next.config.js @@ -13,7 +13,7 @@ module.exports = { ignoreBuildErrors: true, }, eslint: { - ignoreDuringBuilds: true, + ignoreDuringBuilds: false, }, i18n, diff --git a/src/app/(account-pages)/(components)/Nav.tsx b/src/app/(account-pages)/(components)/Nav.tsx index 5ea1fff..d84f75b 100644 --- a/src/app/(account-pages)/(components)/Nav.tsx +++ b/src/app/(account-pages)/(components)/Nav.tsx @@ -12,6 +12,7 @@ export const Nav = () => { "/account", "/my-trips", "/passengers-list", + "/bills", ]; return ( diff --git a/src/app/(account-pages)/bills/BillCard.tsx b/src/app/(account-pages)/bills/BillCard.tsx new file mode 100644 index 0000000..969cbd9 --- /dev/null +++ b/src/app/(account-pages)/bills/BillCard.tsx @@ -0,0 +1,68 @@ +// BillCard.tsx +import React from "react"; +import ButtonPrimary from "@/shared/ButtonPrimary"; +export type BillStatus = "Awaiting Payment" | "Approved" | "Rejected" | "Pending"; +import { BiSolidPlaneAlt } from "react-icons/bi"; +import { FaSimCard } from "react-icons/fa"; +import { BsCart3 } from "react-icons/bs"; +import { MdCurrencyExchange } from "react-icons/md"; +export interface Bill { + title: string; + issuedDate: string; + expirationDate: string; + amount: number; + status: BillStatus; +} + + +interface BillCardProps { + bill: Bill; + onViewDetail: (bill: Bill) => void; // Add onViewDetail prop +} + +const statusStyles: { [key in BillStatus]: string } = { + "Awaiting Payment": "bg-yellow-200 text-yellow-700", + Approved: "bg-green-200 text-green-700", + Rejected: "bg-red-200 text-red-700", + Pending: "bg-blue-200 text-blue-700", +}; + +const BillCard: React.FC = ({ bill, onViewDetail }) => { + return ( +
+
+

+ {bill.title.includes("Tour") && } + {bill.title.includes("SIM Card") && } + {bill.title.includes("Shop") && } + {bill.title.includes("Tasrif") && } + {bill.title} +

+ + {bill.status} + +
+ +
+
+ Issued Date: + {bill.issuedDate} +
+
+ Expiration Date: + {bill.expirationDate} +
+
+ Tour Invoice Amount: + ${bill.amount.toFixed(2)} +
+
+ + onViewDetail(bill)} className="mt-4"> + View Bill + +
+ ); +}; + +export default BillCard; diff --git a/src/app/(account-pages)/bills/[slug]/page.tsx b/src/app/(account-pages)/bills/[slug]/page.tsx new file mode 100644 index 0000000..6d244d7 --- /dev/null +++ b/src/app/(account-pages)/bills/[slug]/page.tsx @@ -0,0 +1,113 @@ +// BillDetailCard.tsx +import React from "react"; +import ButtonPrimary from "@/shared/ButtonPrimary"; +import Button from "@/shared/Button"; + + +export type BillStatus = "Awaiting Payment" | "Approved" | "Rejected" | "Pending"; + +export interface Bill { + title: string; + issuedDate: string; + expirationDate: string; + amount: number; + status: BillStatus; + passengers: { type: string; count: number }[]; + accountNumber: string; + message?: string; + uploadedImage?: { + name: string; + size: string; + src: string; + }; +} + + + +interface BillDetailCardProps { + bill: Bill; +} + +const statusStyles: { [key in BillStatus]: string } = { + "Awaiting Payment": "bg-yellow-200 text-yellow-700", + Approved: "bg-green-200 text-green-700", + Rejected: "bg-red-200 text-red-700", + Pending: "bg-blue-200 text-blue-700", +}; + +const BillDetailCard: React.FC = ({ bill }) => { + return ( +
+
+

{bill.title}

+ + {bill.status} + +
+ + {bill.message && ( +
+

Why was it rejected?

+

{bill.message}

+
+ )} + +
+
+ Issued Date: + {bill.issuedDate} +
+
+ Expiration Date: + {bill.expirationDate} +
+ +
+

Number of Passengers

+ {bill.passengers.map((p, index) => ( +
+ #{p.count} ({p.type}) +
+ ))} +
+ +
+ Tour Price: + ${bill.amount} +
+ +
+

Account Number

+
+ {bill.accountNumber} + +
+
+ + {bill.uploadedImage ? ( +
+

Uploaded Image

+ Uploaded +
+ {bill.uploadedImage.name} + {bill.uploadedImage.size} + +
+
+ ) : ( +
+ +
+ + No File Selected +
+
+ )} +
+ + Submit +
+ ); +}; + +export default BillDetailCard; diff --git a/src/app/(account-pages)/bills/page.tsx b/src/app/(account-pages)/bills/page.tsx new file mode 100644 index 0000000..80d0a8c --- /dev/null +++ b/src/app/(account-pages)/bills/page.tsx @@ -0,0 +1,106 @@ +// BillsPage.tsx +"use client" +import React, { useState } from "react"; +import BillCard from "./BillCard"; +import BillDetailCard from "./[slug]/page"; + + +// types.ts +export type BillStatus = "Awaiting Payment" | "Approved" | "Rejected" | "Pending"; + +export interface Bill { + title: string; + issuedDate: string; + expirationDate: string; + amount: number; + status: BillStatus; + passengers : {} + accountNumber: string, + message? : string + +} + + +const bills: Bill[] = [ + { + title: "Karbala Tour Bill", + issuedDate: "12 Jan 2023", + expirationDate: "10 Jan 2023", + amount: 960, + status: "Awaiting Payment", + passengers: [ + { type: "Adult", count: 3 }, + { type: "Child", count: 2 }, + { type: "Infant", count: 1 }, + ], + accountNumber: "123-456-7890-0123", + }, + { + title: "SIM Card Bill", + issuedDate: "12 Jan 2023", + expirationDate: "10 Jan 2023", + amount: 960, + status: "Approved", + passengers: [ + { type: "Adult", count: 2 }, + { type: "Child", count: 1 }, + ], + accountNumber: "987-654-3210-0123", + }, + { + title: "Shop Bill", + issuedDate: "12 Jan 2023", + expirationDate: "10 Jan 2023", + amount: 960, + status: "Rejected", + passengers: [ + { type: "Adult", count: 1 }, + ], + accountNumber: "456-789-0123-4567", + message: + "The uploaded image does not meet the required quality standards. Please use a higher-resolution photo.", + }, + { + title: "Tasrif Bill", + issuedDate: "12 Jan 2023", + expirationDate: "10 Jan 2023", + amount: 960, + status: "Pending", + passengers: [ + { type: "Adult", count: 3 }, + { type: "Child", count: 2 }, + ], + accountNumber: "321-654-9870-1234", + }, +]; + +const BillsPage: React.FC = () => { + const [selectedBill, setSelectedBill] = useState(null); + + const handleViewDetail = (bill: Bill) => { + setSelectedBill(bill); + }; + + const handleBackToList = () => { + setSelectedBill(null); + }; + + return ( +
+ {selectedBill ? ( +
+ + +
+ ) : ( + bills.map((bill, index) => ( + + )) + )} +
+ ); +}; + +export default BillsPage; diff --git a/src/app/(car-listings)/SectionGridFilterCard.tsx b/src/app/(car-listings)/SectionGridFilterCard.tsx deleted file mode 100644 index 60aaf27..0000000 --- a/src/app/(car-listings)/SectionGridFilterCard.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import React, { FC } from "react"; -import { DEMO_CAR_LISTINGS } from "@/data/listings"; -import { CarDataType } from "@/data/types"; -import Pagination from "@/shared/Pagination"; -import TabFilters from "./TabFilters"; -import Heading2 from "@/shared/Heading2"; -import CarCard from "@/components/CarCard"; - -export interface SectionGridFilterCardProps { - className?: string; - data?: CarDataType[]; -} - -const DEMO_DATA: CarDataType[] = DEMO_CAR_LISTINGS.filter((_, i) => i < 12); - -const SectionGridFilterCard: FC = ({ - className = "", - data = DEMO_DATA, -}) => { - return ( -
- - 233 cars - · - Aug 12 - 18 - - } - /> - -
- -
-
- {data.map((car) => ( - - ))} -
-
- -
-
- ); -}; - -export default SectionGridFilterCard; diff --git a/src/app/(car-listings)/SectionGridHasMap.tsx b/src/app/(car-listings)/SectionGridHasMap.tsx deleted file mode 100644 index 5908844..0000000 --- a/src/app/(car-listings)/SectionGridHasMap.tsx +++ /dev/null @@ -1,112 +0,0 @@ -"use client"; - -import React, { FC, useState } from "react"; -import GoogleMapReact from "google-map-react"; -import { DEMO_CAR_LISTINGS } from "@/data/listings"; -import ButtonClose from "@/shared/ButtonClose"; -import Checkbox from "@/shared/Checkbox"; -import Pagination from "@/shared/Pagination"; -import TabFilters from "./TabFilters"; -import Heading2 from "@/shared/Heading2"; -import CarCardH from "@/components/CarCardH"; -import AnyReactComponent from "@/components/AnyReactComponent/AnyReactComponent"; - -const DEMO_CARS = DEMO_CAR_LISTINGS.filter((_, i) => i < 12); - -export interface SectionGridHasMapProps {} - -const SectionGridHasMap: FC = () => { - const [currentHoverID, setCurrentHoverID] = useState(-1); - const [showFullMapFixed, setShowFullMapFixed] = useState(false); - - return ( -
-
- {/* CARDSSSS */} -
- - 233 cars - · - Aug 12 - 18 - - } - /> -
- -
-
- {DEMO_CARS.map((item) => ( -
setCurrentHoverID((_) => item.id)} - onMouseLeave={() => setCurrentHoverID((_) => -1)} - > - -
- ))} -
-
- -
-
- -
setShowFullMapFixed(true)} - > - - Show map -
- - {/* MAPPPPP */} -
- {showFullMapFixed && ( - setShowFullMapFixed(false)} - className="bg-white absolute z-50 left-3 top-3 shadow-lg rounded-xl w-10 h-10" - /> - )} - -
-
- -
- {/* BELLOW IS MY GOOGLE API KEY -- PLEASE DELETE AND TYPE YOUR API KEY */} - - - {DEMO_CARS.map((item) => ( - - ))} - -
-
-
-
- ); -}; - -export default SectionGridHasMap; diff --git a/src/app/(car-listings)/TabFilters.tsx b/src/app/(car-listings)/TabFilters.tsx deleted file mode 100644 index 22869df..0000000 --- a/src/app/(car-listings)/TabFilters.tsx +++ /dev/null @@ -1,683 +0,0 @@ -"use client"; - -import React, { Fragment, useState } from "react"; -import { Dialog, Popover, Transition } from "@headlessui/react"; -import NcInputNumber from "@/components/NcInputNumber"; -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"; - -// DEMO DATA -const typeOfCar = [ - { name: "Small", description: "$68" }, - { name: "Medium", description: "$128" }, - { name: "Large", description: "$268" }, - { name: "SUV", description: "$268" }, - { name: "Van", description: "$268" }, - { name: "Luxury", description: "$268" }, -]; - -const carSpecifications = [ - { name: "With air conditioning" }, - { name: "Automatic transmission" }, - { name: "Manual transmission" }, - { name: "2 doors" }, - { name: "4+ doors" }, -]; - -// -const mileage = [{ name: "Unlimited" }, { name: "Limited" }]; -const supplier = [ - { name: "Alamo", defaultChecked: true }, - { name: "Avis", defaultChecked: true }, - { name: "Budget" }, - { name: "Dollar" }, -]; -const insurance = [ - { name: "No insurance", defaultChecked: true }, - { name: "Zero excess " }, - { name: "Inclusive" }, -]; - -const TabFilters = () => { - const [isOpenMoreFilter, setisOpenMoreFilter] = useState(false); - const [isOpenMoreFilterMobile, setisOpenMoreFilterMobile] = useState(false); - const [rangePrices, setRangePrices] = useState([0, 1000]); - const [isOnSale, setIsOnSale] = useState(true); - // - const closeModalMoreFilter = () => setisOpenMoreFilter(false); - const openModalMoreFilter = () => setisOpenMoreFilter(true); - // - const closeModalMoreFilterMobile = () => setisOpenMoreFilterMobile(false); - const openModalMoreFilterMobile = () => setisOpenMoreFilterMobile(true); - - const renderXClear = () => { - return ( - - - - - - ); - }; - - const renderTabsTypeOfCars = () => { - return ( - - {({ open, close }) => ( - <> - - Car type - - - - -
-
- {typeOfCar.map((item) => ( -
- -
- ))} -
-
- - Clear - - - Apply - -
-
-
-
- - )} -
- ); - }; - - const renderTabsPriceRage = () => { - return ( - - {({ open, close }) => ( - <> - - - {`$${convertNumbThousand( - rangePrices[0] - )} - $${convertNumbThousand(rangePrices[1])}`}{" "} - - {renderXClear()} - - - -
-
-
- Price per day - setRangePrices(e as number[])} - /> -
- -
-
- -
-
- - $ - -
- -
-
-
- -
-
- - $ - -
- -
-
-
-
-
- - Clear - - - Apply - -
-
-
-
- - )} -
- ); - }; - - const renderTabOnSale = () => { - return ( -
setIsOnSale(!isOnSale)} - > - On sale - {isOnSale && renderXClear()} -
- ); - }; - - const renderTabsGuestsAndBags = () => { - return ( - - {({ open, close }) => ( - <> - - Guests & Bags - - - - -
-
- - -
-
- - Clear - - - Apply - -
-
-
-
- - )} -
- ); - }; - - 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 ( -
-
- {list1.map((item) => ( - - ))} -
-
- {list2.map((item) => ( - - ))} -
-
- ); - }; - - // Morefilter for mobile mode - const renderTabMobileFilter = () => { - return ( -
-
- - Car filters (3) - - {renderXClear()} -
- - - -
- - - - - {/* This element is to trick the browser into centering the modal contents. */} - - -
-
- - Experiences filters - - - - -
- -
-
- {/* ------ */} -
-

Type of car

-
- {renderMoreFilterItem(typeOfCar)} -
-
- - {/* ------ */} -
-

- Car specifications -

-
- {renderMoreFilterItem(carSpecifications)} -
-
- - {/* --------- */} - {/* ---- */} -
-

Range Prices

-
-
-
- setRangePrices(e as number[])} - /> -
- -
-
- -
-
- - $ - -
- -
-
-
- -
-
- - $ - -
- -
-
-
-
-
-
- - {/* ------ */} -
-

- Passengers & Bags -

-
- - -
-
- - {/* ------ */} -
-

Mileage

-
- {renderMoreFilterItem(mileage)} -
-
- - {/* ------ */} -
-

Supplier

-
- {renderMoreFilterItem(supplier)} -
-
- - {/* ------ */} -
-

Insurance

-
- {renderMoreFilterItem(insurance)} -
-
-
-
- -
- - Clear - - - Apply - -
-
-
-
-
-
-
- ); - }; - - // - const renderTabMoreFilter = () => { - return ( -
-
- More filters (3) - {renderXClear()} -
- - - -
- - - - - {/* This element is to trick the browser into centering the modal contents. */} - - -
-
- - More filters - - - - -
- -
-
-
-

- Car specifications -

-
- {renderMoreFilterItem(carSpecifications)} -
-
-
-

Mileage

-
- {renderMoreFilterItem(mileage)} -
-
-
-

Supplier

-
- {renderMoreFilterItem(supplier)} -
-
-
-

Insurance

-
- {renderMoreFilterItem(insurance)} -
-
-
-
- -
- - Clear - - - Apply - -
-
-
-
-
-
-
- ); - }; - - return ( -
-
- {renderTabsTypeOfCars()} - {renderTabsPriceRage()} - {renderTabsGuestsAndBags()} - {renderTabMoreFilter()} -
-
- {renderTabMobileFilter()} - {renderTabOnSale()} -
-
- ); -}; - -export default TabFilters; diff --git a/src/app/(car-listings)/layout.tsx b/src/app/(car-listings)/layout.tsx deleted file mode 100644 index 11856fb..0000000 --- a/src/app/(car-listings)/layout.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import BgGlassmorphism from "@/components/BgGlassmorphism"; -import React, { ReactNode } from "react"; -import SectionHeroArchivePage from "../(server-components)/SectionHeroArchivePage"; -import heroRightImage from "@/images/hero-right-car.png"; -import BackgroundSection from "@/components/BackgroundSection"; -import SectionSliderNewCategories from "@/components/SectionSliderNewCategories"; -import SectionSubscribe2 from "@/components/SectionSubscribe2"; -import SectionGridAuthorBox from "@/components/SectionGridAuthorBox"; - -const Layout = ({ children }: { children: ReactNode }) => { - return ( -
- - - {/* SECTION HERO */} -
- - - 1512 cars - - } - /> -
- - {/* SECTION */} - {children} - -
- {/* SECTION 1 */} -
- - -
- - {/* SECTION */} - - - {/* SECTION */} -
- - -
-
-
- ); -}; - -export default Layout; diff --git a/src/app/(car-listings)/listing-car-map/page.tsx b/src/app/(car-listings)/listing-car-map/page.tsx deleted file mode 100644 index e4b39eb..0000000 --- a/src/app/(car-listings)/listing-car-map/page.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import React, { FC } from "react"; -import SectionGridHasMap from "../SectionGridHasMap"; - -export interface ListingCarMapPageProps {} - -const ListingCarMapPage: FC = () => { - return ( -
- -
- ); -}; - -export default ListingCarMapPage; diff --git a/src/app/(car-listings)/listing-car/page.tsx b/src/app/(car-listings)/listing-car/page.tsx deleted file mode 100644 index b64b1a5..0000000 --- a/src/app/(car-listings)/listing-car/page.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import React, { FC } from "react"; -import SectionGridFilterCard from "../SectionGridFilterCard"; - -export interface ListingCarPageProps {} - -const ListingCarPage: FC = () => { - return ( -
- -
- ); -}; - -export default ListingCarPage; diff --git a/src/app/(client-components)/(Header)/SiteHeader.tsx b/src/app/(client-components)/(Header)/SiteHeader.tsx index acdfd2c..e4637e3 100644 --- a/src/app/(client-components)/(Header)/SiteHeader.tsx +++ b/src/app/(client-components)/(Header)/SiteHeader.tsx @@ -28,7 +28,6 @@ let OPTIONS = { let OBSERVER: IntersectionObserver | null = null; const PAGES_HIDE_HEADER_BORDER: PathName[] = [ "/home-3", - "/listing-car-detail", "/listing-experiences-detail", "/listing-stay-detail", ]; diff --git a/src/app/(client-components)/(HeroSearchForm)/(car-search-form)/RentalCarDatesRangeInput.tsx b/src/app/(client-components)/(HeroSearchForm)/(car-search-form)/RentalCarDatesRangeInput.tsx deleted file mode 100644 index 1c8b013..0000000 --- a/src/app/(client-components)/(HeroSearchForm)/(car-search-form)/RentalCarDatesRangeInput.tsx +++ /dev/null @@ -1,134 +0,0 @@ -"use client"; - -import React, { Fragment, useState } from "react"; -import { FC } from "react"; -import DatePicker from "react-datepicker"; -import { Popover, Transition } from "@headlessui/react"; -import { CalendarIcon } from "@heroicons/react/24/outline"; -import DatePickerCustomHeaderTwoMonth from "@/components/DatePickerCustomHeaderTwoMonth"; -import DatePickerCustomDay from "@/components/DatePickerCustomDay"; -import ClearDataButton from "../ClearDataButton"; -import ButtonSubmit from "../ButtonSubmit"; - -export interface RentalCarDatesRangeInputProps { - className?: string; - fieldClassName?: string; - hasButtonSubmit?: boolean; -} - -const RentalCarDatesRangeInput: FC = ({ - className = "", - fieldClassName = "[ nc-hero-field-padding ]", - hasButtonSubmit = true, -}) => { - const [startDate, setStartDate] = useState( - new Date("2023/03/01") - ); - const [endDate, setEndDate] = useState(new Date("2023/03/16")); - - const onChangeDate = (dates: [Date | null, Date | null]) => { - const [start, end] = dates; - setStartDate(start); - setEndDate(end); - }; - - const renderInput = () => { - return ( - <> -
- -
-
- - {startDate?.toLocaleDateString("en-US", { - month: "short", - day: "2-digit", - }) || "Add dates"} - {endDate - ? " - " + - endDate?.toLocaleDateString("en-US", { - month: "short", - day: "2-digit", - }) - : ""} - - - {"Pick up - Drop off"} - -
- - ); - }; - - return ( - <> - - {({ open }) => ( - <> -
- - {renderInput()} - - {startDate && open && ( - onChangeDate([null, null])} /> - )} - - - {/* BUTTON SUBMIT OF FORM */} - {hasButtonSubmit && ( -
- -
- )} -
- - {open && ( -
- )} - - - -
- ( - - )} - renderDayContents={(day, date) => ( - - )} - /> -
-
-
- - )} -
- - ); -}; - -export default RentalCarDatesRangeInput; diff --git a/src/app/(client-components)/(HeroSearchForm)/(car-search-form)/RentalCarSearchForm.tsx b/src/app/(client-components)/(HeroSearchForm)/(car-search-form)/RentalCarSearchForm.tsx deleted file mode 100644 index 156a3ed..0000000 --- a/src/app/(client-components)/(HeroSearchForm)/(car-search-form)/RentalCarSearchForm.tsx +++ /dev/null @@ -1,70 +0,0 @@ -"use client"; - -import React, { FC, useState } from "react"; -import LocationInput from "../LocationInput"; -import RentalCarDatesRangeInput from "./RentalCarDatesRangeInput"; - -export interface RentalCarSearchFormProps {} - -const RentalCarSearchForm: FC = ({}) => { - const [dropOffLocationType, setDropOffLocationType] = useState< - "same" | "different" - >("different"); - - const renderRadioBtn = () => { - return ( -
-
setDropOffLocationType("different")} - > - Different drop off -
-
setDropOffLocationType("same")} - > - Same drop off -
-
- ); - }; - - const isDdropOffdifferent = dropOffLocationType === "different"; - - return ( -
- {renderRadioBtn()} -
- - {isDdropOffdifferent && ( - <> -
- - - )} -
- -
-
- ); -}; - -export default RentalCarSearchForm; diff --git a/src/app/(client-components)/(HeroSearchForm)/(experiences-search-form)/ExperiencesDateSingleInput.tsx b/src/app/(client-components)/(HeroSearchForm)/(experiences-search-form)/ExperiencesDateSingleInput.tsx deleted file mode 100644 index 705f222..0000000 --- a/src/app/(client-components)/(HeroSearchForm)/(experiences-search-form)/ExperiencesDateSingleInput.tsx +++ /dev/null @@ -1,119 +0,0 @@ -"use client"; - -import React, { Fragment, useState } from "react"; -import { FC } from "react"; -import DatePicker from "react-datepicker"; -import { Popover, Transition } from "@headlessui/react"; -import { CalendarIcon } from "@heroicons/react/24/outline"; -import DatePickerCustomHeaderTwoMonth from "@/components/DatePickerCustomHeaderTwoMonth"; -import DatePickerCustomDay from "@/components/DatePickerCustomDay"; -import ClearDataButton from "../ClearDataButton"; - -export interface ExperiencesDateSingleInputProps { - className?: string; - fieldClassName?: string; -} - -const ExperiencesDateSingleInput: FC = ({ - className = "", - fieldClassName = "[ nc-hero-field-padding ]", -}) => { - const [startDate, setStartDate] = useState( - new Date("2023/03/01") - ); - const [endDate, setEndDate] = useState(new Date("2023/03/16")); - - const onChangeDate = (dates: [Date | null, Date | null]) => { - const [start, end] = dates; - setStartDate(start); - setEndDate(end); - }; - - const renderInput = () => { - return ( - <> -
- -
-
- - {startDate?.toLocaleDateString("en-US", { - month: "short", - day: "2-digit", - }) || "Date"} - {endDate - ? " - " + - endDate?.toLocaleDateString("en-US", { - month: "short", - day: "2-digit", - }) - : ""} - - - {startDate ? "Date" : `Add dates`} - -
- - ); - }; - - return ( - <> - - {({ open }) => ( - <> - - {renderInput()} - {startDate && open && ( - onChangeDate([null, null])} /> - )} - - - {open && ( -
- )} - - - -
- ( - - )} - renderDayContents={(day, date) => ( - - )} - /> -
-
-
- - )} -
- - ); -}; - -export default ExperiencesDateSingleInput; diff --git a/src/app/(client-components)/(HeroSearchForm)/(experiences-search-form)/ExperiencesSearchForm.tsx b/src/app/(client-components)/(HeroSearchForm)/(experiences-search-form)/ExperiencesSearchForm.tsx deleted file mode 100644 index 05093e3..0000000 --- a/src/app/(client-components)/(HeroSearchForm)/(experiences-search-form)/ExperiencesSearchForm.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import React, { FC } from "react"; -import LocationInput from "../LocationInput"; -import GuestsInput from "../GuestsInput"; -import ExperiencesDateSingleInput from "./ExperiencesDateSingleInput"; - -export interface ExperiencesSearchFormProps {} - -const ExperiencesSearchForm: FC = ({}) => { - const renderForm = () => { - return ( -
- -
- -
- - - ); - }; - - return renderForm(); -}; - -export default ExperiencesSearchForm; diff --git a/src/app/(client-components)/(HeroSearchForm)/(flight-search-form)/FlightDateRangeInput.tsx b/src/app/(client-components)/(HeroSearchForm)/(flight-search-form)/FlightDateRangeInput.tsx deleted file mode 100644 index de3b2ba..0000000 --- a/src/app/(client-components)/(HeroSearchForm)/(flight-search-form)/FlightDateRangeInput.tsx +++ /dev/null @@ -1,152 +0,0 @@ -"use client"; - -import React, { Fragment, useState } from "react"; -import { FC } from "react"; -import DatePicker from "react-datepicker"; -import { Popover, Transition } from "@headlessui/react"; -import { CalendarIcon } from "@heroicons/react/24/outline"; -import DatePickerCustomHeaderTwoMonth from "@/components/DatePickerCustomHeaderTwoMonth"; -import DatePickerCustomDay from "@/components/DatePickerCustomDay"; -import ClearDataButton from "../ClearDataButton"; -import ButtonSubmit from "../ButtonSubmit"; - -export interface FlightDateRangeInputProps { - className?: string; - fieldClassName?: string; - hasButtonSubmit?: boolean; - selectsRange?: boolean; -} - -const FlightDateRangeInput: FC = ({ - className = "", - fieldClassName = "[ nc-hero-field-padding ]", - hasButtonSubmit = true, - selectsRange = true, -}) => { - const [startDate, setStartDate] = useState( - new Date("2023/05/01") - ); - const [endDate, setEndDate] = useState(new Date("2023/05/16")); - - const onChangeRangeDate = (dates: [Date | null, Date | null]) => { - const [start, end] = dates; - setStartDate(start); - setEndDate(end); - }; - - const renderInput = () => { - return ( - <> -
- -
-
- - {startDate?.toLocaleDateString("en-US", { - month: "short", - day: "2-digit", - }) || "Add dates"} - {selectsRange && endDate - ? " - " + - endDate?.toLocaleDateString("en-US", { - month: "short", - day: "2-digit", - }) - : ""} - - - {selectsRange ? "Pick up - Drop off" : "Pick up date"} - -
- - ); - }; - - return ( - <> - - {({ open }) => ( - <> -
- - {renderInput()} - - {startDate && open && ( - onChangeRangeDate([null, null])} - /> - )} - - - {/* BUTTON SUBMIT OF FORM */} - {hasButtonSubmit && ( -
- -
- )} -
- - {open && ( -
- )} - - - -
- {selectsRange ? ( - ( - - )} - renderDayContents={(day, date) => ( - - )} - /> - ) : ( - setStartDate(date)} - monthsShown={2} - showPopperArrow={false} - inline - renderCustomHeader={(p) => ( - - )} - renderDayContents={(day, date) => ( - - )} - /> - )} -
-
-
- - )} -
- - ); -}; - -export default FlightDateRangeInput; diff --git a/src/app/(client-components)/(HeroSearchForm)/(flight-search-form)/FlightSearchForm.tsx b/src/app/(client-components)/(HeroSearchForm)/(flight-search-form)/FlightSearchForm.tsx deleted file mode 100644 index 3993770..0000000 --- a/src/app/(client-components)/(HeroSearchForm)/(flight-search-form)/FlightSearchForm.tsx +++ /dev/null @@ -1,246 +0,0 @@ -"use client"; - -import React, { FC, useState } from "react"; -import LocationInput from "../LocationInput"; -import { Popover, Transition } from "@headlessui/react"; -import { ChevronDownIcon } from "@heroicons/react/24/solid"; -import { Fragment } from "react"; -import NcInputNumber from "@/components/NcInputNumber"; -import FlightDateRangeInput from "./FlightDateRangeInput"; -import { GuestsObject } from "../../type"; - -export interface FlightSearchFormProps {} - -const flightClass = [ - { - name: "Economy", - href: "##", - }, - { - name: "Business", - href: "##", - }, - { - name: "Multiple", - href: "##", - }, -]; - -export type TypeDropOffLocationType = "roundTrip" | "oneWay" | ""; - -const FlightSearchForm: FC = ({}) => { - const [dropOffLocationType, setDropOffLocationType] = - useState("roundTrip"); - const [flightClassState, setFlightClassState] = useState("Economy"); - - const [guestAdultsInputValue, setGuestAdultsInputValue] = useState(2); - const [guestChildrenInputValue, setGuestChildrenInputValue] = useState(1); - const [guestInfantsInputValue, setGuestInfantsInputValue] = useState(1); - - const handleChangeData = (value: number, type: keyof GuestsObject) => { - let newValue = { - guestAdults: guestAdultsInputValue, - guestChildren: guestChildrenInputValue, - guestInfants: guestInfantsInputValue, - }; - if (type === "guestAdults") { - setGuestAdultsInputValue(value); - newValue.guestAdults = value; - } - if (type === "guestChildren") { - setGuestChildrenInputValue(value); - newValue.guestChildren = value; - } - if (type === "guestInfants") { - setGuestInfantsInputValue(value); - newValue.guestInfants = value; - } - }; - - const totalGuests = - guestChildrenInputValue + guestAdultsInputValue + guestInfantsInputValue; - - const renderGuest = () => { - return ( - - {({ open }) => ( - <> - - {`${totalGuests || ""} Guests`} - - - - handleChangeData(value, "guestAdults")} - max={10} - min={1} - label="Adults" - desc="Ages 13 or above" - /> - handleChangeData(value, "guestChildren")} - max={4} - label="Children" - desc="Ages 2–12" - /> - - handleChangeData(value, "guestInfants")} - max={4} - label="Infants" - desc="Ages 0–2" - /> - - - - )} - - ); - }; - - const renderSelectClass = () => { - return ( - - {({ open, close }) => ( - <> - - {`${flightClassState}`} - - - - - - - - )} - - ); - }; - - const renderRadioBtn = () => { - return ( -
-
setDropOffLocationType("roundTrip")} - > - Round-trip -
-
setDropOffLocationType("oneWay")} - > - One-way -
- -
- -
- {renderSelectClass()} -
-
- {renderGuest()} -
-
- ); - }; - - const renderForm = () => { - return ( -
- {renderRadioBtn()} -
- -
- -
- -
-
- ); - }; - - return renderForm(); -}; - -export default FlightSearchForm; diff --git a/src/app/(client-components)/(HeroSearchForm)/(real-estate-search-form)/HeroRealEstateSearchForm.tsx b/src/app/(client-components)/(HeroSearchForm)/(real-estate-search-form)/HeroRealEstateSearchForm.tsx deleted file mode 100644 index 3d17238..0000000 --- a/src/app/(client-components)/(HeroSearchForm)/(real-estate-search-form)/HeroRealEstateSearchForm.tsx +++ /dev/null @@ -1,66 +0,0 @@ -"use client"; - -import React, { FC, useState } from "react"; -import RealEstateSearchForm from "./RealEstateSearchForm"; - -export type SearchRealEstateTab = "Buy" | "Rent" | "Sell"; - -export interface HeroRealEstateSearchFormProps { - className?: string; - currentTab?: SearchRealEstateTab; -} - -const HeroRealEstateSearchForm: FC = ({ - className = "", - currentTab = "Buy", -}) => { - const tabs: SearchRealEstateTab[] = ["Buy", "Rent", "Sell"]; - const [tabActive, setTabActive] = useState(currentTab); - - const renderTab = () => { - return ( -
    - {tabs.map((tab) => { - const active = tab === tabActive; - return ( -
  • setTabActive(tab)} - className={`flex items-center cursor-pointer text-sm lg:text-base font-medium ${ - active - ? "" - : "text-neutral-500 hover:text-neutral-700 dark:hover:text-neutral-100" - } `} - key={tab} - > - {active && ( - - )} - {tab} -
  • - ); - })} -
- ); - }; - - const renderForm = () => { - switch (tabActive) { - case "Buy": - return ; - - default: - return ; - } - }; - - return ( -
- {renderTab()} - {renderForm()} -
- ); -}; - -export default HeroRealEstateSearchForm; diff --git a/src/app/(client-components)/(HeroSearchForm)/(real-estate-search-form)/PriceRangeInput.tsx b/src/app/(client-components)/(HeroSearchForm)/(real-estate-search-form)/PriceRangeInput.tsx deleted file mode 100644 index b96255f..0000000 --- a/src/app/(client-components)/(HeroSearchForm)/(real-estate-search-form)/PriceRangeInput.tsx +++ /dev/null @@ -1,137 +0,0 @@ -"use client"; - -import React, { Fragment, useState, FC } from "react"; -import { Popover, Transition } from "@headlessui/react"; -import Slider from "rc-slider"; -import convertNumbThousand from "@/utils/convertNumbThousand"; -import ButtonSubmit from "../ButtonSubmit"; -import { CurrencyDollarIcon } from "@heroicons/react/24/outline"; - -export interface PriceRangeInputProps { - onChange?: (data: any) => void; - fieldClassName?: string; -} - -const PriceRangeInput: FC = ({ - onChange, - fieldClassName = "[ nc-hero-field-padding ]", -}) => { - const [rangePrices, setRangePrices] = useState([100000, 4000000]); - - return ( - - {({ open, close }) => ( - <> -
- document.querySelector("html")?.click()} - > -
- -
-
- - {`$${convertNumbThousand( - rangePrices[0] / 1000 - )}k ~ $${convertNumbThousand(rangePrices[1] / 1000)}k`} - - - Choose price range - -
-
- - {/* BUTTON SUBMIT OF FORM */} -
- -
-
- - {open && ( -
- )} - - - -
-
- Range Price - setRangePrices(e as number[])} - /> -
- -
-
- -
-
- $ -
- -
-
-
- -
-
- $ -
- -
-
-
-
-
-
- - )} -
- ); -}; - -export default PriceRangeInput; diff --git a/src/app/(client-components)/(HeroSearchForm)/(real-estate-search-form)/PropertyTypeSelect.tsx b/src/app/(client-components)/(HeroSearchForm)/(real-estate-search-form)/PropertyTypeSelect.tsx deleted file mode 100644 index 055d3cc..0000000 --- a/src/app/(client-components)/(HeroSearchForm)/(real-estate-search-form)/PropertyTypeSelect.tsx +++ /dev/null @@ -1,126 +0,0 @@ -"use client"; -import React, { Fragment, FC } from "react"; -import { Popover, Transition } from "@headlessui/react"; -import Checkbox from "@/shared/Checkbox"; -import { ClassOfProperties } from "../../type"; -import { HomeIcon } from "@heroicons/react/24/outline"; - -const defaultPropertyType: ClassOfProperties[] = [ - { - name: "Duplex House", - description: "Have a place to yourself", - checked: true, - }, - { - name: "Ferme House", - description: "Have your own room and share some common spaces", - checked: false, - }, - { - name: "Chalet House", - description: - "Have a private or shared room in a boutique hotel, hostel, and more", - checked: false, - }, - { - name: "Maison House", - description: "Stay in a shared space, like a common room", - checked: false, - }, -]; - -export interface PropertyTypeSelectProps { - onChange?: (data: any) => void; - fieldClassName?: string; -} - -const PropertyTypeSelect: FC = ({ - onChange, - fieldClassName = "[ nc-hero-field-padding ]", -}) => { - const [typeOfProperty, setTypeOfProperty] = - React.useState(defaultPropertyType); - - let typeOfPropertyText = ""; - if (typeOfProperty && typeOfProperty.length > 0) { - typeOfPropertyText = typeOfProperty - .filter((item) => item.checked) - .map((item) => { - return item.name; - }) - .join(", "); - } - return ( - - {({ open, close }) => ( - <> - document.querySelector("html")?.click()} - > -
- -
-
- - - {typeOfPropertyText || `Type`} - - - - Property type - -
-
- - {open && ( -
- )} - - - -
-
- {typeOfProperty.map((item, index) => ( -
- { - const newState = typeOfProperty.map((item, i) => { - if (i === index) { - return { ...item, checked: e }; - } - return item; - }); - setTypeOfProperty(() => { - return newState; - }); - onChange && onChange(newState); - }} - /> -
- ))} -
-
-
-
- - )} -
- ); -}; - -export default PropertyTypeSelect; diff --git a/src/app/(client-components)/(HeroSearchForm)/(real-estate-search-form)/RealEstateSearchForm.tsx b/src/app/(client-components)/(HeroSearchForm)/(real-estate-search-form)/RealEstateSearchForm.tsx deleted file mode 100644 index 8b2699b..0000000 --- a/src/app/(client-components)/(HeroSearchForm)/(real-estate-search-form)/RealEstateSearchForm.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import React, { FC } from "react"; -import LocationInput from "../LocationInput"; -import PriceRangeInput from "./PriceRangeInput"; -import PropertyTypeSelect from "./PropertyTypeSelect"; - -export interface RealEstateSearchFormProps {} - -const RealEstateSearchForm: FC = ({}) => { - const renderForm = () => { - return ( -
- - -
- -
- - - ); - }; - - return renderForm(); -}; - -export default RealEstateSearchForm; diff --git a/src/app/(client-components)/(HeroSearchForm)/GuestsInput.tsx b/src/app/(client-components)/(HeroSearchForm)/GuestsInput.tsx index 3cb55a9..5cb15d0 100644 --- a/src/app/(client-components)/(HeroSearchForm)/GuestsInput.tsx +++ b/src/app/(client-components)/(HeroSearchForm)/GuestsInput.tsx @@ -1,5 +1,4 @@ - -"use client" +"use client"; import React, { Fragment, useContext, useEffect, useState } from "react"; import { Popover, Transition } from "@headlessui/react"; @@ -10,7 +9,7 @@ import ButtonSubmit from "./ButtonSubmit"; import { PathName } from "@/routers/types"; import { UserPlusIcon } from "@heroicons/react/24/outline"; import { GuestsObject } from "../type"; -import { Context } from "@/components/contexts/tourDetails"; +import { Context, useToursContext } from "@/components/contexts/tourDetails"; export interface GuestsInputProps { fieldClassName?: string; @@ -26,22 +25,38 @@ const GuestsInput: FC = ({ hasButtonSubmit = true, }) => { const [guestAdultsInputValue, setGuestAdultsInputValue] = useState(0); - const { passengers, details , setPassengers } = useContext(Context); + const [guestChildrenInputValue, setGuestChildrenInputValue] = useState(0); + const [guestInfantsInputValue, setGuestInfantsInputValue] = useState(0); + const { details, setPassengers } = useToursContext() const handleChangeData = (value: number, type: keyof GuestsObject) => { - let newValue = { + const newValue = { guestAdults: guestAdultsInputValue, + guestChildren: guestChildrenInputValue, + guestInfants: guestInfantsInputValue, }; - setGuestAdultsInputValue(value); - newValue.guestAdults = value; - setPassengers(value) + + if (type === "guestAdults") setGuestAdultsInputValue(value); + else if (type === "guestChildren") setGuestChildrenInputValue(value); + else if (type === "guestInfants") setGuestInfantsInputValue(value); + + setPassengers({ + guestAdults: newValue.guestAdults, + guestChildren: newValue.guestChildren, + guestInfants: newValue.guestInfants, + }); }; - useEffect(()=>{ - setPassengers(guestAdultsInputValue) + useEffect(() => { + setPassengers({ + guestAdults: guestAdultsInputValue, + guestChildren: guestChildrenInputValue, + guestInfants: guestInfantsInputValue, + }); + }, [guestAdultsInputValue, guestChildrenInputValue, guestInfantsInputValue]); - } , []) + const totalGuests = guestAdultsInputValue + guestChildrenInputValue + guestInfantsInputValue; return ( @@ -60,27 +75,31 @@ const GuestsInput: FC = ({
- {guestAdultsInputValue || ""} Passengers + {totalGuests || ""} Guests - {guestAdultsInputValue ? "Passengers" : "Add passengers"} + {totalGuests ? "Guests" : "Add guests"}
- {!!guestAdultsInputValue && open && ( + {!!totalGuests && open && ( { setGuestAdultsInputValue(0); - setPassengers(0) + setGuestChildrenInputValue(0); + setGuestInfantsInputValue(0); + setPassengers({ guestAdults: 0, guestChildren: 0, guestInfants: 0 }); }} /> )} - {/* BUTTON SUBMIT OF FORM */} {hasButtonSubmit && (
- +
)} @@ -107,6 +126,24 @@ const GuestsInput: FC = ({ label="Adults" desc="Ages 13 or above" /> + handleChangeData(value, "guestChildren")} + max={4} + min={0} + label="Children" + desc="Ages 2–12" + /> + handleChangeData(value, "guestInfants")} + max={4} + min={0} + label="Infants" + desc="Ages 0–2" + /> diff --git a/src/app/(client-components)/(HeroSearchFormSmall)/(car-search-form)/RentalCarDatesRangeInput.tsx b/src/app/(client-components)/(HeroSearchFormSmall)/(car-search-form)/RentalCarDatesRangeInput.tsx deleted file mode 100644 index 6b58673..0000000 --- a/src/app/(client-components)/(HeroSearchFormSmall)/(car-search-form)/RentalCarDatesRangeInput.tsx +++ /dev/null @@ -1,129 +0,0 @@ -"use client"; - -import React, { Fragment, useState, FC } from "react"; -import DatePicker from "react-datepicker"; -import { Popover, Transition } from "@headlessui/react"; -import DatePickerCustomHeaderTwoMonth from "@/components/DatePickerCustomHeaderTwoMonth"; -import DatePickerCustomDay from "@/components/DatePickerCustomDay"; -import ClearDataButton from "../ClearDataButton"; -import ButtonSubmit from "../ButtonSubmit"; - -export interface RentalCarDatesRangeInputProps { - className?: string; - fieldClassName?: string; - hasButtonSubmit?: boolean; -} - -const RentalCarDatesRangeInput: FC = ({ - className = "", - fieldClassName = "[ nc-hero-field-padding--small ]", - hasButtonSubmit = true, -}) => { - const [startDate, setStartDate] = useState( - new Date("2023/03/01") - ); - const [endDate, setEndDate] = useState(new Date("2023/03/16")); - - const onChangeDate = (dates: [Date | null, Date | null]) => { - const [start, end] = dates; - setStartDate(start); - setEndDate(end); - }; - - const renderInput = () => { - return ( - <> -
- - {startDate?.toLocaleDateString("en-US", { - month: "short", - day: "2-digit", - }) || "Add dates"} - {endDate - ? " - " + - endDate?.toLocaleDateString("en-US", { - month: "short", - day: "2-digit", - }) - : ""} - - - {"Pick up - Drop off"} - -
- - ); - }; - - return ( - <> - - {({ open }) => ( - <> -
- - {renderInput()} - - {startDate && open && ( - onChangeDate([null, null])} /> - )} - - - {/* BUTTON SUBMIT OF FORM */} - {hasButtonSubmit && ( -
- -
- )} -
- - {open && ( -
- )} - - - -
- ( - - )} - renderDayContents={(day, date) => ( - - )} - /> -
-
-
- - )} -
- - ); -}; - -export default RentalCarDatesRangeInput; diff --git a/src/app/(client-components)/(HeroSearchFormSmall)/(car-search-form)/RentalCarSearchForm.tsx b/src/app/(client-components)/(HeroSearchFormSmall)/(car-search-form)/RentalCarSearchForm.tsx deleted file mode 100644 index 751571a..0000000 --- a/src/app/(client-components)/(HeroSearchFormSmall)/(car-search-form)/RentalCarSearchForm.tsx +++ /dev/null @@ -1,72 +0,0 @@ -"use client"; - -import React, { FC, useState } from "react"; -import LocationInput from "../LocationInput"; -import RentalCarDatesRangeInput from "./RentalCarDatesRangeInput"; - -export interface RentalCarSearchFormProps {} - -const RentalCarSearchForm: FC = ({}) => { - const [dropOffLocationType, setDropOffLocationType] = useState< - "same" | "different" - >("different"); - - const renderRadioBtn = () => { - return ( -
-
setDropOffLocationType("same")} - > - Same drop off -
-
setDropOffLocationType("different")} - > - Different drop off -
-
- ); - }; - - const renderForm = () => { - return ( -
- {renderRadioBtn()} -
- - {dropOffLocationType === "different" && ( - <> -
- - - )} -
- -
-
- ); - }; - - return renderForm(); -}; - -export default RentalCarSearchForm; diff --git a/src/app/(client-components)/(HeroSearchFormSmall)/(experiences-search-form)/ExperiencesDateSingleInput.tsx b/src/app/(client-components)/(HeroSearchFormSmall)/(experiences-search-form)/ExperiencesDateSingleInput.tsx deleted file mode 100644 index d2cadd0..0000000 --- a/src/app/(client-components)/(HeroSearchFormSmall)/(experiences-search-form)/ExperiencesDateSingleInput.tsx +++ /dev/null @@ -1,114 +0,0 @@ -"use client"; - -import React, { Fragment, useState, FC } from "react"; -import DatePicker from "react-datepicker"; -import { Popover, Transition } from "@headlessui/react"; -import DatePickerCustomHeaderTwoMonth from "@/components/DatePickerCustomHeaderTwoMonth"; -import DatePickerCustomDay from "@/components/DatePickerCustomDay"; -import ClearDataButton from "../ClearDataButton"; - -export interface ExperiencesDateSingleInputProps { - className?: string; - fieldClassName?: string; -} - -const ExperiencesDateSingleInput: FC = ({ - className = "", - fieldClassName = "[ nc-hero-field-padding--small ]", -}) => { - const [startDate, setStartDate] = useState( - new Date("2023/03/01") - ); - const [endDate, setEndDate] = useState(new Date("2023/03/16")); - - const onChangeDate = (dates: [Date | null, Date | null]) => { - const [start, end] = dates; - setStartDate(start); - setEndDate(end); - }; - - const renderInput = () => { - return ( - <> -
- - {startDate?.toLocaleDateString("en-US", { - month: "short", - day: "2-digit", - }) || "Date"} - {endDate - ? " - " + - endDate?.toLocaleDateString("en-US", { - month: "short", - day: "2-digit", - }) - : ""} - - - {startDate ? "Date" : `Add dates`} - -
- - ); - }; - - return ( - <> - - {({ open }) => ( - <> - - {renderInput()} - {startDate && open && ( - onChangeDate([null, null])} /> - )} - - - {open && ( -
- )} - - - -
- ( - - )} - renderDayContents={(day, date) => ( - - )} - /> -
-
-
- - )} -
- - ); -}; - -export default ExperiencesDateSingleInput; diff --git a/src/app/(client-components)/(HeroSearchFormSmall)/(experiences-search-form)/ExperiencesSearchForm.tsx b/src/app/(client-components)/(HeroSearchFormSmall)/(experiences-search-form)/ExperiencesSearchForm.tsx deleted file mode 100644 index 7fc2417..0000000 --- a/src/app/(client-components)/(HeroSearchFormSmall)/(experiences-search-form)/ExperiencesSearchForm.tsx +++ /dev/null @@ -1,29 +0,0 @@ -"use client"; - -import React, { FC } from "react"; -import LocationInput from "../LocationInput"; -import GuestsInput from "../GuestsInput"; -import ExperiencesDateSingleInput from "./ExperiencesDateSingleInput"; - -export interface ExperiencesSearchFormProps {} - -const ExperiencesSearchForm: FC = ({}) => { - const renderForm = () => { - return ( -
- setDateFocused(true)} - className="flex-[1.5]" - /> -
- -
- - - ); - }; - - return renderForm(); -}; - -export default ExperiencesSearchForm; diff --git a/src/app/(client-components)/(HeroSearchFormSmall)/(flight-search-form)/FlightDateRangeInput.tsx b/src/app/(client-components)/(HeroSearchFormSmall)/(flight-search-form)/FlightDateRangeInput.tsx deleted file mode 100644 index 7f0a7de..0000000 --- a/src/app/(client-components)/(HeroSearchFormSmall)/(flight-search-form)/FlightDateRangeInput.tsx +++ /dev/null @@ -1,148 +0,0 @@ -"use client"; - -import React, { Fragment, useState } from "react"; -import { FC } from "react"; -import DatePicker from "react-datepicker"; -import { Popover, Transition } from "@headlessui/react"; -import DatePickerCustomHeaderTwoMonth from "@/components/DatePickerCustomHeaderTwoMonth"; -import DatePickerCustomDay from "@/components/DatePickerCustomDay"; -import ClearDataButton from "../ClearDataButton"; -import ButtonSubmit from "../ButtonSubmit"; - -export interface FlightDateRangeInputProps { - className?: string; - fieldClassName?: string; - hasButtonSubmit?: boolean; - selectsRange?: boolean; -} - -const FlightDateRangeInput: FC = ({ - className = "", - fieldClassName = "[ nc-hero-field-padding--small ]", - hasButtonSubmit = true, - selectsRange = true, -}) => { - const [startDate, setStartDate] = useState( - new Date("2023/05/01") - ); - const [endDate, setEndDate] = useState(new Date("2023/05/16")); - - const onChangeRangeDate = (dates: [Date | null, Date | null]) => { - const [start, end] = dates; - setStartDate(start); - setEndDate(end); - }; - - const renderInput = () => { - return ( - <> -
- - {startDate?.toLocaleDateString("en-US", { - month: "short", - day: "2-digit", - }) || "Add dates"} - {selectsRange && endDate - ? " - " + - endDate?.toLocaleDateString("en-US", { - month: "short", - day: "2-digit", - }) - : ""} - - - {selectsRange ? "Pick up - Drop off" : "Pick up date"} - -
- - ); - }; - - return ( - <> - - {({ open }) => ( - <> -
- - {renderInput()} - - {startDate && open && ( - onChangeRangeDate([null, null])} - /> - )} - - - {/* BUTTON SUBMIT OF FORM */} - {hasButtonSubmit && ( -
- -
- )} -
- - {open && ( -
- )} - - - -
- {selectsRange ? ( - ( - - )} - renderDayContents={(day, date) => ( - - )} - /> - ) : ( - setStartDate(date)} - monthsShown={2} - showPopperArrow={false} - inline - renderCustomHeader={(p) => ( - - )} - renderDayContents={(day, date) => ( - - )} - /> - )} -
-
-
- - )} -
- - ); -}; - -export default FlightDateRangeInput; diff --git a/src/app/(client-components)/(HeroSearchFormSmall)/(flight-search-form)/FlightSearchForm.tsx b/src/app/(client-components)/(HeroSearchFormSmall)/(flight-search-form)/FlightSearchForm.tsx deleted file mode 100644 index e020585..0000000 --- a/src/app/(client-components)/(HeroSearchFormSmall)/(flight-search-form)/FlightSearchForm.tsx +++ /dev/null @@ -1,247 +0,0 @@ -"use client"; - -import React, { FC, useState } from "react"; -import LocationInput from "../LocationInput"; -import { Popover, Transition } from "@headlessui/react"; -import { ChevronDownIcon } from "@heroicons/react/24/solid"; -import { Fragment } from "react"; -import NcInputNumber from "@/components/NcInputNumber"; -import FlightDateRangeInput from "./FlightDateRangeInput"; -import { GuestsObject } from "../../type"; - -export interface FlightSearchFormProps {} - -const flightClass = [ - { - name: "Economy", - href: "##", - }, - { - name: "Business", - href: "##", - }, - { - name: "Multiple", - href: "##", - }, -]; - -const FlightSearchForm: FC = ({}) => { - const [dropOffLocationType, setDropOffLocationType] = useState< - "roundTrip" | "oneWay" | "" - >("roundTrip"); - const [flightClassState, setFlightClassState] = useState("Economy"); - const [guestAdultsInputValue, setGuestAdultsInputValue] = useState(2); - const [guestChildrenInputValue, setGuestChildrenInputValue] = useState(1); - const [guestInfantsInputValue, setGuestInfantsInputValue] = useState(1); - - const handleChangeData = (value: number, type: keyof GuestsObject) => { - let newValue = { - guestAdults: guestAdultsInputValue, - guestChildren: guestChildrenInputValue, - guestInfants: guestInfantsInputValue, - }; - if (type === "guestAdults") { - setGuestAdultsInputValue(value); - newValue.guestAdults = value; - } - if (type === "guestChildren") { - setGuestChildrenInputValue(value); - newValue.guestChildren = value; - } - if (type === "guestInfants") { - setGuestInfantsInputValue(value); - newValue.guestInfants = value; - } - }; - - const totalGuests = - guestChildrenInputValue + guestAdultsInputValue + guestInfantsInputValue; - - const renderGuest = () => { - return ( -
- - {({ open }) => ( - <> - - {`${totalGuests || ""} Guests`} - - - - handleChangeData(value, "guestAdults")} - max={10} - min={1} - label="Adults" - desc="Ages 13 or above" - /> - - handleChangeData(value, "guestChildren") - } - max={4} - label="Children" - desc="Ages 2–12" - /> - - - handleChangeData(value, "guestInfants") - } - max={4} - label="Infants" - desc="Ages 0–2" - /> - - - - )} - -
- ); - }; - - const renderSelectClass = () => { - return ( - - ); - }; - - const renderRadioBtn = () => { - return ( -
-
setDropOffLocationType("roundTrip")} - > - Round-trip -
-
setDropOffLocationType("oneWay")} - > - One-way -
- -
- -
- {renderSelectClass()} -
-
- {renderGuest()} -
-
- ); - }; - - const renderForm = () => { - return ( -
- {renderRadioBtn()} -
- -
- -
- -
-
- ); - }; - - return renderForm(); -}; - -export default FlightSearchForm; diff --git a/src/app/(experience-listings)/SectionGridFilterCard.tsx b/src/app/(experience-listings)/SectionGridFilterCard.tsx deleted file mode 100644 index b5af41a..0000000 --- a/src/app/(experience-listings)/SectionGridFilterCard.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import React, { FC } from "react"; -import { DEMO_EXPERIENCES_LISTINGS } from "@/data/listings"; -import { ExperiencesDataType, StayDataType } from "@/data/types"; -import Pagination from "@/shared/Pagination"; -import TabFilters from "./TabFilters"; -import Heading2 from "@/shared/Heading2"; -import ExperiencesCard from "@/components/ExperiencesCard"; - -export interface SectionGridFilterCardProps { - className?: string; - data?: StayDataType[]; -} - -const DEMO_DATA: ExperiencesDataType[] = DEMO_EXPERIENCES_LISTINGS.filter( - (_, i) => i < 8 -); - -const SectionGridFilterCard: FC = ({ - className = "", - data = DEMO_DATA, -}) => { - return ( -
- - 233 experiences - · - Aug 12 - 18 - ·2 Guests - - } - /> - -
- -
-
- {data.map((stay) => ( - - ))} -
-
- -
-
- ); -}; - -export default SectionGridFilterCard; diff --git a/src/app/(experience-listings)/SectionGridHasMap.tsx b/src/app/(experience-listings)/SectionGridHasMap.tsx deleted file mode 100644 index 4024f63..0000000 --- a/src/app/(experience-listings)/SectionGridHasMap.tsx +++ /dev/null @@ -1,113 +0,0 @@ -"use client"; - -import React, { FC, useState } from "react"; -import AnyReactComponent from "@/components/AnyReactComponent/AnyReactComponent"; -import GoogleMapReact from "google-map-react"; -import { DEMO_EXPERIENCES_LISTINGS } from "@/data/listings"; -import ButtonClose from "@/shared/ButtonClose"; -import Checkbox from "@/shared/Checkbox"; -import Pagination from "@/shared/Pagination"; -import TabFilters from "./TabFilters"; -import Heading2 from "@/shared/Heading2"; -import ExperiencesCardH from "@/components/ExperiencesCardH"; - -const DEMO_EXPERIENCES = DEMO_EXPERIENCES_LISTINGS.filter((_, i) => i < 12); - -export interface SectionGridHasMapProps {} - -const SectionGridHasMap: FC = () => { - const [currentHoverID, setCurrentHoverID] = useState(-1); - const [showFullMapFixed, setShowFullMapFixed] = useState(false); - - return ( -
-
- {/* CARDSSSS */} -
- - 233 experiences - · - Aug 12 - 18 - ·2 Guests - - } - /> -
- -
-
- {DEMO_EXPERIENCES.map((item) => ( -
setCurrentHoverID((_) => item.id)} - onMouseLeave={() => setCurrentHoverID((_) => -1)} - > - -
- ))} -
-
- -
-
- -
setShowFullMapFixed(true)} - > - - Show map -
- - {/* MAPPPPP */} -
- {showFullMapFixed && ( - setShowFullMapFixed(false)} - className="bg-white absolute z-50 left-3 top-3 shadow-lg rounded-xl w-10 h-10" - /> - )} - -
-
- -
- {/* BELLOW IS MY GOOGLE API KEY -- PLEASE DELETE AND TYPE YOUR API KEY */} - - - {DEMO_EXPERIENCES.map((item) => ( - - ))} - -
-
-
-
- ); -}; - -export default SectionGridHasMap; diff --git a/src/app/(experience-listings)/TabFilters.tsx b/src/app/(experience-listings)/TabFilters.tsx deleted file mode 100644 index 88bae72..0000000 --- a/src/app/(experience-listings)/TabFilters.tsx +++ /dev/null @@ -1,538 +0,0 @@ -"use client"; - -import React, { Fragment, useState } from "react"; -import { Dialog, Popover, 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"; - -// DEMO DATA -const typeOfExpriences = [ - { - name: "Food & drink", - description: "Short description for the experience", - }, - { - name: "Art and culture", - description: "Short description for the experience", - }, - { - name: "Nature and outdoors", - description: "Short description for the experience", - }, - { - name: "Sports", - description: "Short description for the experience", - }, -]; - -const timeOfdays = [ - { - name: "Morning", - description: "Start before 12pm", - }, - { - name: "Afternoon", - description: "Start after 12pm", - }, - { - name: "Evening", - description: "Start after 5pm", - }, -]; - -// -const moreFilter1 = typeOfExpriences; -const moreFilter2 = timeOfdays; - -const TabFilters = () => { - const [isOpenMoreFilter, setisOpenMoreFilter] = useState(false); - // - const [isOnSale, setIsOnSale] = useState(true); - const [rangePrices, setRangePrices] = useState([0, 1000]); - // - const closeModalMoreFilter = () => setisOpenMoreFilter(false); - const openModalMoreFilter = () => setisOpenMoreFilter(true); - - const renderXClear = () => { - return ( - - - - - - ); - }; - - const renderTabsTypeOfPlace = () => { - return ( - - {({ open, close }) => ( - <> - - Type of experiences - - - - -
-
- {typeOfExpriences.map((item) => ( -
- -
- ))} -
-
- - Clear - - - Apply - -
-
-
-
- - )} -
- ); - }; - - const renderTabsTimeOfDay = () => { - return ( - - {({ open, close }) => ( - <> - - Time of day - - - - -
-
- {timeOfdays.map((item) => ( -
- -
- ))} -
-
- - Clear - - - Apply - -
-
-
-
- - )} -
- ); - }; - - const renderTabsPriceRage = () => { - return ( - - {({ open, close }) => ( - <> - - - {`$${convertNumbThousand( - rangePrices[0] - )} - $${convertNumbThousand(rangePrices[1])}`}{" "} - - {renderXClear()} - - - -
-
-
- Price per day - setRangePrices(e as number[])} - /> -
- -
-
- -
-
- - $ - -
- -
-
-
- -
-
- - $ - -
- -
-
-
-
-
- - Clear - - - Apply - -
-
-
-
- - )} -
- ); - }; - - const renderTabOnSale = () => { - return ( -
setIsOnSale(!isOnSale)} - > - On sale - {isOnSale && renderXClear()} -
- ); - }; - - 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 ( -
-
- {list1.map((item) => ( - - ))} -
-
- {list2.map((item) => ( - - ))} -
-
- ); - }; - - const renderTabMobileFilter = () => { - return ( -
-
- - Experiences filters (3) - - {renderXClear()} -
- - - -
- - - - - {/* This element is to trick the browser into centering the modal contents. */} - - -
-
- - Experiences filters - - - - -
- -
-
-
-

- Type of experiences -

-
- {renderMoreFilterItem(moreFilter1)} -
-
-
-

Time of day

-
- {renderMoreFilterItem(moreFilter2)} -
-
- - {/* --------- */} - {/* ---- */} -
-

Range Prices

-
-
-
- setRangePrices(e as number[])} - /> -
- -
-
- -
-
- - $ - -
- -
-
-
- -
-
- - $ - -
- -
-
-
-
-
-
-
-
- -
- - Clear - - - Apply - -
-
-
-
-
-
-
- ); - }; - - return ( -
-
- {renderTabsTypeOfPlace()} - {renderTabsPriceRage()} - {renderTabsTimeOfDay()} - {renderTabOnSale()} -
-
- {renderTabMobileFilter()} - {renderTabOnSale()} -
-
- ); -}; - -export default TabFilters; diff --git a/src/app/(experience-listings)/layout.tsx b/src/app/(experience-listings)/layout.tsx deleted file mode 100644 index b90ca90..0000000 --- a/src/app/(experience-listings)/layout.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import BackgroundSection from "@/components/BackgroundSection"; -import BgGlassmorphism from "@/components/BgGlassmorphism"; -import SectionGridAuthorBox from "@/components/SectionGridAuthorBox"; -import SectionSliderNewCategories from "@/components/SectionSliderNewCategories"; -import SectionSubscribe2 from "@/components/SectionSubscribe2"; -import React, { ReactNode } from "react"; -import SectionHeroArchivePage from "../(server-components)/SectionHeroArchivePage"; - -const Layout = ({ children }: { children: ReactNode }) => { - return ( -
- - - {/* SECTION HERO */} -
- - - 1599 experiences - - } - /> -
- - {children} - -
- {/* SECTION 1 */} -
- - -
- - {/* SECTION */} - - - {/* SECTION */} -
- - -
-
-
- ); -}; - -export default Layout; diff --git a/src/app/(experience-listings)/listing-experiences-map/page.tsx b/src/app/(experience-listings)/listing-experiences-map/page.tsx deleted file mode 100644 index efce76f..0000000 --- a/src/app/(experience-listings)/listing-experiences-map/page.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import React, { FC } from "react"; -import SectionGridHasMap from "../SectionGridHasMap"; - -export interface ListingExperiencesMapPageProps {} - -const ListingExperiencesMapPage: FC = ({}) => { - return ( -
- -
- ); -}; - -export default ListingExperiencesMapPage; diff --git a/src/app/(experience-listings)/listing-experiences/page.tsx b/src/app/(experience-listings)/listing-experiences/page.tsx deleted file mode 100644 index 9a58e6b..0000000 --- a/src/app/(experience-listings)/listing-experiences/page.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import React, { FC } from "react"; -import SectionGridFilterCard from "../SectionGridFilterCard"; - -export interface ListingExperiencesPageProps {} - -const ListingExperiencesPage: FC = ({}) => { - return ( -
- -
- ); -}; - -export default ListingExperiencesPage; diff --git a/src/app/(home)/home-2/page.tsx b/src/app/(home)/home-2/page.tsx deleted file mode 100644 index 0e77df9..0000000 --- a/src/app/(home)/home-2/page.tsx +++ /dev/null @@ -1,195 +0,0 @@ -import SectionSliderNewCategories from "@/components/SectionSliderNewCategories"; -import React from "react"; -import SectionSubscribe2 from "@/components/SectionSubscribe2"; -import SectionOurFeatures from "@/components/SectionOurFeatures"; -import SectionHowItWork from "@/components/SectionHowItWork"; -import BackgroundSection from "@/components/BackgroundSection"; -import { TaxonomyType } from "@/data/types"; -import SectionGridAuthorBox from "@/components/SectionGridAuthorBox"; -// -import logo1 from "@/images/logos/nomal/1.png"; -import logo1Dark from "@/images/logos/dark/1.png"; -// -import logo2 from "@/images/logos/nomal/2.png"; -import logo2Dark from "@/images/logos/dark/2.png"; -// -import logo3 from "@/images/logos/nomal/3.png"; -import logo3Dark from "@/images/logos/dark/3.png"; -// -import logo4 from "@/images/logos/nomal/4.png"; -import logo4Dark from "@/images/logos/dark/4.png"; -// -import logo5 from "@/images/logos/nomal/5.png"; -import logo5Dark from "@/images/logos/dark/5.png"; -// -import HIW1img from "@/images/HIW2-1.png"; -import HIW2img from "@/images/HIW2-2.png"; -import HIW3img from "@/images/HIW2-3.png"; -import HIW1imgDark from "@/images/HIW2-1-dark.png"; -import HIW2imgDark from "@/images/HIW2-2-dark.png"; -import HIW3imgDark from "@/images/HIW2-3-dark.png"; -import rightImgPng from "@/images/our-features-2.png"; - -import SectionGridFeatureProperty from "../SectionGridFeatureProperty"; -import SectionDowloadApp from "../SectionDowloadApp"; -import SectionHero2 from "@/app/(server-components)/SectionHero2"; -import Image from "next/image"; - -const DEMO_CATS_2: TaxonomyType[] = [ - { - id: "1", - href: "/listing-real-estate", - name: "Enjoy the great cold", - taxonomy: "category", - count: 188288, - thumbnail: - "https://images.pexels.com/photos/5764100/pexels-photo-5764100.jpeg?auto=compress&cs=tinysrgb&dpr=3&h=750&w=1260", - }, - { - id: "2", - href: "/listing-real-estate", - name: "Sleep in a floating way", - taxonomy: "category", - count: 188288, - thumbnail: - "https://images.pexels.com/photos/2869499/pexels-photo-2869499.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260", - }, - { - id: "3", - href: "/listing-real-estate", - name: "In the billionaire's house", - taxonomy: "category", - count: 188288, - thumbnail: - "https://images.pexels.com/photos/7031413/pexels-photo-7031413.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260", - }, - { - id: "4", - href: "/listing-real-estate", - name: "Cool in the deep forest", - taxonomy: "category", - count: 188288, - thumbnail: - "https://images.pexels.com/photos/247532/pexels-photo-247532.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260", - }, - { - id: "5", - href: "/listing-real-estate", - name: "In the billionaire's house", - taxonomy: "category", - count: 188288, - thumbnail: - "https://images.pexels.com/photos/7031413/pexels-photo-7031413.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260", - }, - { - id: "6", - href: "/listing-real-estate", - name: "Sleep in a floating way", - taxonomy: "category", - count: 188288, - thumbnail: - "https://images.pexels.com/photos/2869499/pexels-photo-2869499.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260", - }, - { - id: "7", - href: "/listing-real-estate", - name: "In the billionaire's house", - taxonomy: "category", - count: 188288, - thumbnail: - "https://images.pexels.com/photos/7031413/pexels-photo-7031413.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260", - }, -]; - -function PageHome2() { - return ( -
-
- - -
-
- logo1 - logo1 -
-
- logo4 - logo4 -
-
- logo2 - logo2 -
-
- logo3 - logo3 -
- -
- logo5 - logo5 -
-
- - - -
- - -
- - - - - - - -
- - -
- - - - -
-
- ); -} - -export default PageHome2; diff --git a/src/app/(home)/home-3/page.tsx b/src/app/(home)/home-3/page.tsx deleted file mode 100644 index 918d173..0000000 --- a/src/app/(home)/home-3/page.tsx +++ /dev/null @@ -1,104 +0,0 @@ -import React from "react"; -import SectionSubscribe2 from "@/components/SectionSubscribe2"; -import BackgroundSection from "@/components/BackgroundSection"; -import BgGlassmorphism from "@/components/BgGlassmorphism"; -import { TaxonomyType } from "@/data/types"; -import SectionGridAuthorBox from "@/components/SectionGridAuthorBox"; -import SectionGridCategoryBox from "@/components/SectionGridCategoryBox"; -import SectionHero3 from "@/app/(server-components)/SectionHero3"; -import CardCategory6 from "@/components/CardCategory6"; -import SectionGridFeaturePlaces from "@/components/SectionGridFeaturePlaces"; - -const DEMO_CATS_2: TaxonomyType[] = [ - { - id: "1", - href: "/listing-stay", - name: "Enjoy the great cold", - taxonomy: "category", - count: 188288, - thumbnail: - "https://images.pexels.com/photos/5764100/pexels-photo-5764100.jpeg?auto=compress&cs=tinysrgb&dpr=3&h=750&w=1260", - }, - { - id: "222", - href: "/listing-stay", - name: "Sleep in a floating way", - taxonomy: "category", - count: 188288, - thumbnail: - "https://images.pexels.com/photos/2869499/pexels-photo-2869499.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260", - }, - { - id: "3", - href: "/listing-stay", - name: "In the billionaire's house", - taxonomy: "category", - count: 188288, - thumbnail: - "https://images.pexels.com/photos/7031413/pexels-photo-7031413.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260", - }, - { - id: "4", - href: "/listing-stay", - name: "Cool in the deep forest", - taxonomy: "category", - count: 188288, - thumbnail: - "https://images.pexels.com/photos/247532/pexels-photo-247532.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260", - }, - { - id: "5", - href: "/listing-stay", - name: "In the billionaire's house", - taxonomy: "category", - count: 188288, - thumbnail: - "https://images.pexels.com/photos/7031413/pexels-photo-7031413.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260", - }, -]; - -function PageHome3() { - return ( -
- {/* GLASSMOPHIN */} - - - {/* SECTION HERO */} -
- -
- -
- {/* SECTION 1 */} -
-
- -
-
- - -
-
- -
-
- - {/* SECTION */} - - - {/* SECTION */} -
- - -
- - - - {/* SECTION */} - -
-
- ); -} - -export default PageHome3; diff --git a/src/app/(listing-detail)/SectionDateRange.tsx b/src/app/(listing-detail)/SectionDateRange.tsx deleted file mode 100644 index b386355..0000000 --- a/src/app/(listing-detail)/SectionDateRange.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import React, { FC, Fragment, useState } from "react"; -import DatePicker from "react-datepicker"; -import DatePickerCustomHeaderTwoMonth from "@/components/DatePickerCustomHeaderTwoMonth"; -import DatePickerCustomDay from "@/components/DatePickerCustomDay"; - -const SectionDateRange = () => { - const [startDate, setStartDate] = useState( - new Date("2023/02/06") - ); - const [endDate, setEndDate] = useState(new Date("2023/02/23")); - const onChangeDate = (dates: [Date | null, Date | null]) => { - const [start, end] = dates; - setStartDate(start); - setEndDate(end); - }; - - const renderSectionCheckIndate = () => { - return ( -
- {/* HEADING */} -
-

Availability

- - Prices may increase on weekends or holidays - -
-
- {/* CONTENT */} - -
- ( - - )} - renderDayContents={(day, date) => ( - - )} - /> -
-
- ); - }; - - // return renderSectionCheckIndate(); -}; - -export default SectionDateRange; diff --git a/src/app/(listing-detail)/layout.tsx b/src/app/(listing-detail)/layout.tsx deleted file mode 100644 index 5c675b8..0000000 --- a/src/app/(listing-detail)/layout.tsx +++ /dev/null @@ -1,77 +0,0 @@ -"use client"; - -import BackgroundSection from "@/components/BackgroundSection"; -import ListingImageGallery from "@/components/listing-image-gallery/ListingImageGallery"; -import SectionSliderNewCategories from "@/components/SectionSliderNewCategories"; -import SectionSubscribe2 from "@/components/SectionSubscribe2"; -import { usePathname, useRouter, useSearchParams } from "next/navigation"; -import React, { ReactNode, useEffect, useState } from "react"; -import MobileFooterSticky from "./(components)/MobileFooterSticky"; -import { imageGallery as listingStayImageGallery } from "./listing-stay-detail/constant"; -import { imageGallery as listingCarImageGallery } from "./listing-car-detail/constant"; -import { imageGallery as listingExperienceImageGallery } from "./listing-experiences-detail/constant"; -import { Route } from "next"; -import axiosInstance from "@/components/api/axios"; -import axios from "axios"; - -const DetailtLayout = ({ children }: { children: ReactNode }) => { - const router = useRouter(); - const thisPathname = usePathname(); - const searchParams = useSearchParams(); - const modal = searchParams?.get("modal"); - - const handleCloseModalImageGallery = () => { - let params = new URLSearchParams(document.location.search); - params.delete("modal"); - router.push(`${thisPathname}/?${params.toString()}` as Route); - }; - - const getImageGalleryListing = () => { - - - if (thisPathname?.includes("/listing-stay-detail")) { - return listingStayImageGallery; - } - if (thisPathname?.includes("/listing-car-detail")) { - return listingCarImageGallery; - } - if (thisPathname?.includes("/listing-experiences-detail")) { - return listingExperienceImageGallery; - } - - return []; - }; - - - return ( -
- - -
{children}
- - {/* OTHER SECTION */} -
-
- - -
- -
- - {/* STICKY FOOTER MOBILE */} - -
- ); -}; - -export default DetailtLayout; diff --git a/src/app/(listing-detail)/listing-car-detail/RentalCarDatesRangeInput.tsx b/src/app/(listing-detail)/listing-car-detail/RentalCarDatesRangeInput.tsx deleted file mode 100644 index 028fb4b..0000000 --- a/src/app/(listing-detail)/listing-car-detail/RentalCarDatesRangeInput.tsx +++ /dev/null @@ -1,118 +0,0 @@ -"use client"; - -import React, { Fragment, useState } from "react"; -import { FC } from "react"; -import DatePicker from "react-datepicker"; -import { Popover, Transition } from "@headlessui/react"; -import { CalendarIcon } from "@heroicons/react/24/outline"; -import DatePickerCustomHeaderTwoMonth from "@/components/DatePickerCustomHeaderTwoMonth"; -import DatePickerCustomDay from "@/components/DatePickerCustomDay"; -import ClearDataButton from "@/app/(client-components)/(HeroSearchForm)/ClearDataButton"; - -export interface RentalCarDatesRangeInputProps { - className?: string; -} - -const RentalCarDatesRangeInput: FC = ({ - className = "", -}) => { - const [startDate, setStartDate] = useState( - new Date("2023/03/01") - ); - const [endDate, setEndDate] = useState(new Date("2023/03/16")); - - const onChangeDate = (dates: [Date | null, Date | null]) => { - const [start, end] = dates; - setStartDate(start); - setEndDate(end); - }; - - const renderInput = () => { - return ( - <> -
- -
-
- - {startDate?.toLocaleDateString("en-US", { - month: "short", - day: "2-digit", - }) || "Add dates"} - {endDate - ? " - " + - endDate?.toLocaleDateString("en-US", { - month: "short", - day: "2-digit", - }) - : ""} - - - {"Pick up - Drop off"} - -
- - ); - }; - - return ( - <> - - {({ open }) => ( - <> -
- - {renderInput()} - - {startDate && open && ( - onChangeDate([null, null])} /> - )} - -
- - - -
- ( - - )} - renderDayContents={(day, date) => ( - - )} - /> -
-
-
- - )} -
- - ); -}; - -export default RentalCarDatesRangeInput; diff --git a/src/app/(listing-detail)/listing-car-detail/constant.ts b/src/app/(listing-detail)/listing-car-detail/constant.ts deleted file mode 100644 index 0f13b85..0000000 --- a/src/app/(listing-detail)/listing-car-detail/constant.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { ListingGalleryImage } from "@/components/listing-image-gallery/utils/types"; -import carUtilities1 from "@/images/carUtilities/1.png"; -import carUtilities2 from "@/images/carUtilities/2.png"; -import carUtilities3 from "@/images/carUtilities/3.png"; -import carUtilities4 from "@/images/carUtilities/4.png"; -import carUtilities5 from "@/images/carUtilities/5.png"; -import carUtilities6 from "@/images/carUtilities/6.png"; -import carUtilities7 from "@/images/carUtilities/7.png"; -import carUtilities8 from "@/images/carUtilities/8.png"; - -export const PHOTOS: string[] = [ - "https://images.pexels.com/photos/381292/pexels-photo-381292.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260", - "https://images.pexels.com/photos/2526128/pexels-photo-2526128.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260", - "https://images.pexels.com/photos/2827753/pexels-photo-2827753.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260", - "https://images.pexels.com/photos/1637859/pexels-photo-1637859.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260", - "https://images.pexels.com/photos/257851/pexels-photo-257851.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260", - "https://images.pexels.com/photos/457418/pexels-photo-457418.jpeg?auto=compress&cs=tinysrgb&w=1600", - "https://images.pexels.com/photos/1707820/pexels-photo-1707820.jpeg?auto=compress&cs=tinysrgb&w=1600", - "https://images.pexels.com/photos/712618/pexels-photo-712618.jpeg?auto=compress&cs=tinysrgb&w=1600", - "https://images.pexels.com/photos/3802508/pexels-photo-3802508.jpeg?auto=compress&cs=tinysrgb&w=1600", - "https://images.pexels.com/photos/945443/pexels-photo-945443.jpeg?auto=compress&cs=tinysrgb&w=1600", - "https://images.pexels.com/photos/1054211/pexels-photo-1054211.jpeg?auto=compress&cs=tinysrgb&w=1600", - "https://images.pexels.com/photos/189454/pexels-photo-189454.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260", - "https://images.pexels.com/photos/193995/pexels-photo-193995.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260", - "https://images.pexels.com/photos/575386/pexels-photo-575386.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260", - "https://images.pexels.com/photos/248687/pexels-photo-248687.jpeg?auto=compress&cs=tinysrgb&w=1600", - "https://images.pexels.com/photos/326259/pexels-photo-326259.jpeg?auto=compress&cs=tinysrgb&w=1600", - "https://images.pexels.com/photos/2127733/pexels-photo-2127733.jpeg?auto=compress&cs=tinysrgb&w=1600", - "https://images.pexels.com/photos/2882234/pexels-photo-2882234.jpeg?auto=compress&cs=tinysrgb&w=1600", - "https://images.pexels.com/photos/752615/pexels-photo-752615.jpeg?auto=compress&cs=tinysrgb&w=1600", - "https://images.pexels.com/photos/1210622/pexels-photo-1210622.jpeg?auto=compress&cs=tinysrgb&w=1600", - "https://images.pexels.com/photos/303316/pexels-photo-303316.jpeg?auto=compress&cs=tinysrgb&w=1600", - "https://images.pexels.com/photos/136872/pexels-photo-136872.jpeg?auto=compress&cs=tinysrgb&w=1600", -]; - -export const includes_demo = [ - { name: "Free cancellation up to 48 hours before pick-up" }, - { name: "Collision Damage Waiver with $214 deductible" }, - { name: "Theft Protection with $19,999 excess" }, - { name: "Unlimited mileage" }, - { - name: "Car interiors and exteriors cleaned with disinfectant before pick-up", - }, - { name: "Masks are required at the pick-up location" }, -]; - -export const Amenities_demos = [ - { name: "59 MPG Combined, 58 City/60 Hwy", icon: carUtilities1 }, - { - name: "Forward Collision-Avoidance Assist with Pedestrian Detection (FCA-Ped)", - icon: carUtilities2, - }, - { name: "139-hp gas/electric combined", icon: carUtilities3 }, - { name: "Proximity Key with push button start", icon: carUtilities4 }, - { name: "8-inch color touchscreen display audio", icon: carUtilities5 }, - { name: "Smart Cruise Control with Stop & Go (SCC)", icon: carUtilities6 }, - { name: "LED Daytime Running Lights (DRL)", icon: carUtilities7 }, - { name: "Blind-Spot Collision Warning (BCW)", icon: carUtilities8 }, -]; - -export const imageGallery: ListingGalleryImage[] = [...PHOTOS].map( - (item, index): ListingGalleryImage => { - return { - id: index, - url: item, - }; - } -); diff --git a/src/app/(listing-detail)/listing-car-detail/page.tsx b/src/app/(listing-detail)/listing-car-detail/page.tsx deleted file mode 100644 index 726444b..0000000 --- a/src/app/(listing-detail)/listing-car-detail/page.tsx +++ /dev/null @@ -1,542 +0,0 @@ -"use client"; - -import React, { FC, useState } from "react"; -import { ArrowRightIcon, Squares2X2Icon } from "@heroicons/react/24/outline"; -import CommentListing from "@/components/CommentListing"; -import FiveStartIconForRate from "@/components/FiveStartIconForRate"; -import StartRating from "@/components/StartRating"; -import Avatar from "@/shared/Avatar"; -import Badge from "@/shared/Badge"; -import ButtonCircle from "@/shared/ButtonCircle"; -import ButtonPrimary from "@/shared/ButtonPrimary"; -import ButtonSecondary from "@/shared/ButtonSecondary"; -import Input from "@/shared/Input"; -import Image from "next/image"; -import { Amenities_demos, includes_demo, PHOTOS } from "./constant"; -import LikeSaveBtns from "@/components/LikeSaveBtns"; -import { usePathname, useRouter } from "next/navigation"; -import SectionDateRange from "../SectionDateRange"; -import RentalCarDatesRangeInput from "./RentalCarDatesRangeInput"; -import { Route } from "next"; - -export interface ListingCarDetailPageProps {} - -const ListingCarDetailPage: FC = ({}) => { - // USE STATE - - const thisPathname = usePathname(); - const router = useRouter(); - - const handleOpenModalImageGallery = () => { - router.push(`${thisPathname}/?modal=PHOTO_TOUR_SCROLLABLE` as Route); - }; - - const renderSection1 = () => { - return ( -
- {/* 1 */} -
- - -
- - {/* 2 */} -

- BMW 3 Series Sedan -

- - {/* 3 */} -
- - · - - - Tokyo, Jappan - -
- - {/* 4 */} -
- - - Car owner{" "} - - Kevin Francis - - -
- - {/* 5 */} -
- - {/* 6 */} -
-
- - 4 seats -
-
- - Auto gearbox -
-
- - 2 bags -
-
-
- ); - }; - - // - const renderSectionTienIch = () => { - return ( -
-
-

- Vehicle parameters & utilities{" "} -

- - Questions are at the heart of making things great. - -
-
- {/* 6 */} -
- {/* TIEN ICH 1 */} - {Amenities_demos.map((item, index) => ( -
-
- -
- {item.name} -
- ))} -
-
- ); - }; - - const renderSection2 = () => { - return ( -
-

Car descriptions

-
-
-

- Until the all-new TUCSON hits the dealer showrooms you can check it - out in our Showroom Walkaround video. Watch the video and join our - product specialist as he gives you an up-close look of our latest - SUV -
-
- Questions are at the heart of making things great. Watch our - celebrity-filled TV ad and you’ll see that when we say “everything,” - we mean everything. -

-
-
- ); - }; - - const renderSection3 = () => { - return ( -
-
-

Include

- - Included in the price - -
-
- {/* 6 */} -
- {includes_demo - .filter((_, i) => i < 12) - .map((item) => ( -
- - {item.name} -
- ))} -
-
- ); - }; - - const renderSection5 = () => { - return ( -
- {/* HEADING */} -

Car Owner

-
- - {/* host */} -
- -
- - Kevin Francis - -
- - · - 12 places -
-
-
- - {/* desc */} - - Providing lake views, The Symphony 9 Tam Coc in Ninh Binh provides - accommodation, an outdoor swimming pool, a bar, a shared lounge, a - garden and barbecue facilities... - - - {/* info */} -
-
- - - - Joined in March 2016 -
-
- - - - Response rate - 100% -
-
- - - - - Fast response - within a few hours -
-
- - {/* == */} -
-
- See host profile -
-
- ); - }; - - const renderSection6 = () => { - return ( -
- {/* HEADING */} -

Reviews (23 reviews)

-
- - {/* Content */} -
- -
- - - - -
-
- - {/* comment */} -
- - - - -
- View more 20 reviews -
-
-
- ); - }; - - const renderSection7 = () => { - return ( -
- {/* HEADING */} -
-

Location

- - San Diego, CA, United States of America (SAN-San Diego Intl.) - -
-
- - {/* MAP */} -
-
- -
-
-
- ); - }; - - const renderSection8 = () => { - return ( -
- {/* HEADING */} -

Things to know

-
- - {/* CONTENT */} -
-

Cancellation policy

- - Lock in this fantastic price today, cancel free of charge anytime. - Reserve now and pay at pick-up. - -
-
- - {/* CONTENT */} -
-

Special Note

- - We asked ourselves, “How can we make the dash not only look better, - but also give the driver a better look outside?” The unexpected - answer is having no hood above the available 10.25-inch digital - instrument cluster... - -
-
- ); - }; - - const renderSidebarPrice = () => { - return ( -
- {/* PRICE */} -
- - $19 - - /day - - - -
- - {/* FORM */} -
- - - - {/* SUM */} -
-
- $19 x 3 day - $57 -
- -
-
- Total - $199 -
-
- - {/* SUBMIT */} - Reserve -
- ); - }; - - const renderSidebarDetail = () => { - return ( -
- - Pick up and drop off - -
-
- - - -
-
-
- - Monday, August 12 · 10:00 - - - Saint Petersburg City Center - -
-
- - Monday, August 16 · 10:00 - - - Saint Petersburg City Center - -
-
-
-
- ); - }; - - return ( -
- {/* SINGLE HEADER */} -
-
-
- photo 0 -
-
- - {/* */} -
- photo 1 -
-
- - {/* */} - {PHOTOS.filter((_, i) => i >= 2 && i < 4).map((item, index) => ( -
= 2 ? "block" : "" - }`} - > -
- photos -
- - {/* OVERLAY */} -
-
- ))} - -
- - - - Show all photos - -
-
-
- - {/* MAIn */} -
- {/* CONTENT */} -
- {renderSection1()} -
{renderSidebarDetail()}
- {renderSectionTienIch()} - {renderSection2()} - {renderSection3()} - - - {renderSection5()} - {renderSection6()} - {renderSection7()} - {renderSection8()} -
- - {/* SIDEBAR */} -
- {renderSidebarDetail()} -
- {renderSidebarPrice()} -
-
-
-
- ); -}; - -export default ListingCarDetailPage; diff --git a/src/app/(listing-detail)/listing-experiences-detail/GuestsInput.tsx b/src/app/(listing-detail)/listing-experiences-detail/GuestsInput.tsx deleted file mode 100644 index df55385..0000000 --- a/src/app/(listing-detail)/listing-experiences-detail/GuestsInput.tsx +++ /dev/null @@ -1,122 +0,0 @@ -"use client"; - -import React, { Fragment, FC, useState } from "react"; -import { Popover, Transition } from "@headlessui/react"; -import NcInputNumber from "@/components/NcInputNumber"; -import { UserPlusIcon } from "@heroicons/react/24/outline"; -import ClearDataButton from "@/app/(client-components)/(HeroSearchForm)/ClearDataButton"; -import { GuestsObject } from "@/app/(client-components)/type"; - -export interface GuestsInputProps { - className?: string; -} - -const GuestsInput: FC = ({ className = "flex-1" }) => { - const [guestAdultsInputValue, setGuestAdultsInputValue] = useState(2); - const [guestChildrenInputValue, setGuestChildrenInputValue] = useState(1); - const [guestInfantsInputValue, setGuestInfantsInputValue] = useState(1); - - const handleChangeData = (value: number, type: keyof GuestsObject) => { - let newValue = { - guestAdults: guestAdultsInputValue, - guestChildren: guestChildrenInputValue, - guestInfants: guestInfantsInputValue, - }; - if (type === "guestAdults") { - setGuestAdultsInputValue(value); - newValue.guestAdults = value; - } - if (type === "guestChildren") { - setGuestChildrenInputValue(value); - newValue.guestChildren = value; - } - if (type === "guestInfants") { - setGuestInfantsInputValue(value); - newValue.guestInfants = value; - } - }; - - const totalGuests = - guestChildrenInputValue + guestAdultsInputValue + guestInfantsInputValue; - - return ( - - {({ open }) => ( - <> -
- -
- -
-
- - {totalGuests || ""} Guests - - - {totalGuests ? "Guests" : "Add guests"} - -
- - {!!totalGuests && open && ( - { - setGuestAdultsInputValue(0); - setGuestChildrenInputValue(0); - setGuestInfantsInputValue(0); - }} - /> - )} -
-
- - - - handleChangeData(value, "guestAdults")} - max={10} - min={1} - label="Adults" - desc="Ages 13 or above" - /> - handleChangeData(value, "guestChildren")} - max={4} - label="Children" - desc="Ages 2–12" - /> - - handleChangeData(value, "guestInfants")} - max={4} - label="Infants" - desc="Ages 0–2" - /> - - - - )} -
- ); -}; - -export default GuestsInput; diff --git a/src/app/(listing-detail)/listing-experiences-detail/StayDatesRangeInput.tsx b/src/app/(listing-detail)/listing-experiences-detail/StayDatesRangeInput.tsx deleted file mode 100644 index 7b00e12..0000000 --- a/src/app/(listing-detail)/listing-experiences-detail/StayDatesRangeInput.tsx +++ /dev/null @@ -1,109 +0,0 @@ -"use client"; - -import React, { Fragment, useState, FC } from "react"; -import { Popover, Transition } from "@headlessui/react"; -import { CalendarIcon } from "@heroicons/react/24/outline"; -import DatePickerCustomHeaderTwoMonth from "@/components/DatePickerCustomHeaderTwoMonth"; -import DatePickerCustomDay from "@/components/DatePickerCustomDay"; -import DatePicker from "react-datepicker"; -import ClearDataButton from "@/app/(client-components)/(HeroSearchForm)/ClearDataButton"; - -export interface StayDatesRangeInputProps { - className?: string; -} - -const StayDatesRangeInput: FC = ({ - className = "flex-1", -}) => { - const [startDate, setStartDate] = useState( - new Date("2023/02/06") - ); - const [endDate, setEndDate] = useState(new Date("2023/02/23")); - // - - const onChangeDate = (dates: [Date | null, Date | null]) => { - const [start, end] = dates; - setStartDate(start); - setEndDate(end); - }; - - const renderInput = () => { - return ( - <> -
- -
-
- - {startDate?.toLocaleDateString("en-US", { - month: "short", - day: "2-digit", - }) || "Add dates"} - {endDate - ? " - " + - endDate?.toLocaleDateString("en-US", { - month: "short", - day: "2-digit", - }) - : ""} - - - {"Check in - Check out"} - -
- - ); - }; - - return ( - - {({ open }) => ( - <> - - {renderInput()} - {startDate && open && ( - onChangeDate([null, null])} /> - )} - - - - -
- ( - - )} - renderDayContents={(day, date) => ( - - )} - /> -
-
-
- - )} -
- ); -}; - -export default StayDatesRangeInput; diff --git a/src/app/(listing-detail)/listing-experiences-detail/constant.ts b/src/app/(listing-detail)/listing-experiences-detail/constant.ts deleted file mode 100644 index ec030ec..0000000 --- a/src/app/(listing-detail)/listing-experiences-detail/constant.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { ListingGalleryImage } from "@/components/listing-image-gallery/utils/types"; - -export const PHOTOS: string[] = [ - "https://images.pexels.com/photos/3225531/pexels-photo-3225531.jpeg?auto=compress&cs=tinysrgb&dpr=3&h=750&w=1260", - "https://images.pexels.com/photos/1154638/pexels-photo-1154638.jpeg?auto=compress&cs=tinysrgb&dpr=3&h=750&w=1260", - "https://images.pexels.com/photos/3851949/pexels-photo-3851949.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940", - "https://images.pexels.com/photos/3019019/pexels-photo-3019019.jpeg?auto=compress&cs=tinysrgb&dpr=3&h=750&w=1260", - "https://images.pexels.com/photos/6438752/pexels-photo-6438752.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260", - "https://images.pexels.com/photos/1320686/pexels-photo-1320686.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260", - "https://images.pexels.com/photos/261394/pexels-photo-261394.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260", - "https://images.pexels.com/photos/2861361/pexels-photo-2861361.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260", - "https://images.pexels.com/photos/2677398/pexels-photo-2677398.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260", - "https://images.pexels.com/photos/4348078/pexels-photo-4348078.jpeg?auto=compress&cs=tinysrgb&w=1600", - "https://images.pexels.com/photos/3825527/pexels-photo-3825527.jpeg?auto=compress&cs=tinysrgb&w=1600", - "https://images.pexels.com/photos/4706134/pexels-photo-4706134.jpeg?auto=compress&cs=tinysrgb&w=1600", - "https://images.pexels.com/photos/3825578/pexels-photo-3825578.jpeg?auto=compress&cs=tinysrgb&w=1600", - "https://images.pexels.com/photos/123335/pexels-photo-123335.jpeg?auto=compress&cs=tinysrgb&w=1600", - "https://images.pexels.com/photos/3761124/pexels-photo-3761124.jpeg?auto=compress&cs=tinysrgb&w=1600", - "https://images.pexels.com/photos/8926846/pexels-photo-8926846.jpeg?auto=compress&cs=tinysrgb&w=1600", - "https://images.pexels.com/photos/4706139/pexels-photo-4706139.jpeg?auto=compress&cs=tinysrgb&w=1600", - "https://images.pexels.com/photos/7003624/pexels-photo-7003624.jpeg?auto=compress&cs=tinysrgb&w=1600", -]; - -export const includes_demo = [ - { name: "Set Menu Lunch on boat" }, - { name: "Express Bus From Hanoi To Halong and Return" }, - { name: "Mineral Water On Express Bus" }, - { name: "Kayak or Bamboo Boat. Life Jacket." }, - { name: "Halong Bay Entrance Ticket" }, -]; - -export const imageGallery: ListingGalleryImage[] = [...PHOTOS].map( - (item, index): ListingGalleryImage => { - return { - id: index, - url: item, - }; - } -); diff --git a/src/app/(listing-detail)/listing-experiences-detail/page.tsx b/src/app/(listing-detail)/listing-experiences-detail/page.tsx deleted file mode 100644 index f8b1e92..0000000 --- a/src/app/(listing-detail)/listing-experiences-detail/page.tsx +++ /dev/null @@ -1,505 +0,0 @@ -"use client"; - -import React, { FC, useState } from "react"; -import { ArrowRightIcon, Squares2X2Icon } from "@heroicons/react/24/outline"; -import CommentListing from "@/components/CommentListing"; -import FiveStartIconForRate from "@/components/FiveStartIconForRate"; -import Avatar from "@/shared/Avatar"; -import Badge from "@/shared/Badge"; -import ButtonCircle from "@/shared/ButtonCircle"; -import ButtonPrimary from "@/shared/ButtonPrimary"; -import ButtonSecondary from "@/shared/ButtonSecondary"; -import Input from "@/shared/Input"; -import { usePathname, useRouter } from "next/navigation"; -import LikeSaveBtns from "@/components/LikeSaveBtns"; -import StartRating from "@/components/StartRating"; -import { includes_demo, PHOTOS } from "./constant"; -import Image from "next/image"; -import StayDatesRangeInput from "./StayDatesRangeInput"; -import GuestsInput from "./GuestsInput"; -import SectionDateRange from "../SectionDateRange"; -import { Route } from "next"; - -export interface ListingExperiencesDetailPageProps {} - -const ListingExperiencesDetailPage: FC< - ListingExperiencesDetailPageProps -> = ({}) => { - const thisPathname = usePathname(); - const router = useRouter(); - - const handleOpenModalImageGallery = () => { - router.push(`${thisPathname}/?modal=PHOTO_TOUR_SCROLLABLE` as Route); - }; - - const renderSection1 = () => { - return ( -
- {/* 1 */} -
- - -
- - {/* 2 */} -

- Trang An Boat Tour & Mua Cave -

- - {/* 3 */} -
- - · - - - Tokyo, Jappan - -
- - {/* 4 */} -
- - - Hosted by{" "} - - Kevin Francis - - -
- - {/* 5 */} -
- - {/* 6 */} -
-
- - 3.5 hours -
-
- - Up to 10 people -
-
- - English, VietNames -
-
-
- ); - }; - - const renderSection2 = () => { - return ( -
-

Experiences descriptions

-
-
-

- TRANG AN BOAT TOUR & MUA CAVE CLIMBING TOUR FROM HANOI -
-
- 07:30 – 08:00 – Our guide will meet you at your hotel/stay and start - a 120km comfortable Limousine bus journey through the verdant - landscape. Stopover for a rest on the way. -
-
- BAI DINH PAGODA EXPLORER. -
-
- 10:30 – Arrive Bai Dinh pagoda complex, get on electric cars to - visit massive architecture. -
-
- 12:15 – Enjoy the buffet lunch at our restaurant, a great place to - savor the flavours of Vietnamese food. -
-
- TRANG AN TOUR ON BOAT. -
-
- 13:30 – Visit Trang An Grottoes, get on a rowing boat traveling - along the river with scenic mountain and green fields landscape. -
-
- MUA CAVE HIKING. TAKE PICTURE -
-
- 15:45 – Arrive at Mua Cave and start an amazing trek up to the top - of Ngoa Long mountain. -
-
- 17:30 – 20:00 – Return to our Limousine bus and then come back to - Hanoi. Drop you off at your hotel/stay. Other things to note -
-
- It is one full day tour. Start from 07.30 AM and finish at 20.00. We - just put one hour and default departure time because we have many - other tours. IF you need any further details -

-
-
- ); - }; - - const renderSection3 = () => { - return ( -
-
-

Include

- - Included in the price - -
-
- {/* 6 */} -
- {includes_demo - .filter((_, i) => i < 12) - .map((item) => ( -
- - {item.name} -
- ))} -
-
- ); - }; - - const renderSection5 = () => { - return ( -
- {/* HEADING */} -

Host Information

-
- - {/* host */} -
- -
- - Kevin Francis - -
- - · - 12 places -
-
-
- - {/* desc */} - - Providing lake views, The Symphony 9 Tam Coc in Ninh Binh provides - accommodation, an outdoor swimming pool, a bar, a shared lounge, a - garden and barbecue facilities... - - - {/* info */} -
-
- - - - Joined in March 2016 -
-
- - - - Response rate - 100% -
-
- - - - - Fast response - within a few hours -
-
- - {/* == */} -
-
- See host profile -
-
- ); - }; - - const renderSection6 = () => { - return ( -
- {/* HEADING */} -

Reviews (23 reviews)

-
- - {/* Content */} -
- -
- - - - -
-
- - {/* comment */} -
- - - - -
- View more 20 reviews -
-
-
- ); - }; - - const renderSection7 = () => { - return ( -
- {/* HEADING */} -
-

Location

- - San Diego, CA, United States of America (SAN-San Diego Intl.) - -
-
- - {/* MAP */} -
-
- -
-
-
- ); - }; - - const renderSection8 = () => { - return ( -
- {/* HEADING */} -

Things to know

-
- - {/* CONTENT */} -
-

Cancellation policy

- - Any experience can be canceled and fully refunded within 24 hours of - purchase, or at least 7 days before the experience starts. - -
-
- - {/* CONTENT */} -
-

Guest requirements

- - Up to 10 guests ages 4 and up can attend. Parents may also bring - children under 2 years of age. - -
-
- - {/* CONTENT */} -
-

What to bring

-
-
    -
  • - Formal Wear To Visit Bai Dinh Pagoda Be ready before 7.30 Am. -
  • -
  • We will pick up from 07.30 to 08.00 AM
  • -
-
-
-
- ); - }; - - const renderSidebar = () => { - return ( -
- {/* PRICE */} -
- - $19 - - /person - - - -
- - {/* FORM */} - {/* FORM */} -
- -
- - - - {/* SUM */} -
-
- $19 x 3 adults - $57 -
-
- Service charge - $0 -
-
-
- Total - $199 -
-
- - {/* SUBMIT */} - Reserve -
- ); - }; - - return ( -
- {/* SINGLE HEADER */} -
-
-
- photo 1 -
-
- {PHOTOS.filter((_, i) => i >= 1 && i < 4).map((item, index) => ( -
= 2 ? "block" : "" - }`} - > -
- photos -
- - {/* OVERLAY */} -
-
- ))} - -
- - - Show all photos - -
-
-
- - {/* MAIn */} -
- {/* CONTENT */} -
- {renderSection1()} - {renderSection2()} - {renderSection3()} - - - {renderSection5()} - {renderSection6()} - {renderSection7()} - {renderSection8()} -
- - {/* SIDEBAR */} -
-
{renderSidebar()}
-
-
-
- ); -}; - -export default ListingExperiencesDetailPage; diff --git a/src/app/(listing-detail)/listing-stay-detail/GuestsInput.tsx b/src/app/(listing-detail)/listing-stay-detail/GuestsInput.tsx deleted file mode 100644 index df55385..0000000 --- a/src/app/(listing-detail)/listing-stay-detail/GuestsInput.tsx +++ /dev/null @@ -1,122 +0,0 @@ -"use client"; - -import React, { Fragment, FC, useState } from "react"; -import { Popover, Transition } from "@headlessui/react"; -import NcInputNumber from "@/components/NcInputNumber"; -import { UserPlusIcon } from "@heroicons/react/24/outline"; -import ClearDataButton from "@/app/(client-components)/(HeroSearchForm)/ClearDataButton"; -import { GuestsObject } from "@/app/(client-components)/type"; - -export interface GuestsInputProps { - className?: string; -} - -const GuestsInput: FC = ({ className = "flex-1" }) => { - const [guestAdultsInputValue, setGuestAdultsInputValue] = useState(2); - const [guestChildrenInputValue, setGuestChildrenInputValue] = useState(1); - const [guestInfantsInputValue, setGuestInfantsInputValue] = useState(1); - - const handleChangeData = (value: number, type: keyof GuestsObject) => { - let newValue = { - guestAdults: guestAdultsInputValue, - guestChildren: guestChildrenInputValue, - guestInfants: guestInfantsInputValue, - }; - if (type === "guestAdults") { - setGuestAdultsInputValue(value); - newValue.guestAdults = value; - } - if (type === "guestChildren") { - setGuestChildrenInputValue(value); - newValue.guestChildren = value; - } - if (type === "guestInfants") { - setGuestInfantsInputValue(value); - newValue.guestInfants = value; - } - }; - - const totalGuests = - guestChildrenInputValue + guestAdultsInputValue + guestInfantsInputValue; - - return ( - - {({ open }) => ( - <> -
- -
- -
-
- - {totalGuests || ""} Guests - - - {totalGuests ? "Guests" : "Add guests"} - -
- - {!!totalGuests && open && ( - { - setGuestAdultsInputValue(0); - setGuestChildrenInputValue(0); - setGuestInfantsInputValue(0); - }} - /> - )} -
-
- - - - handleChangeData(value, "guestAdults")} - max={10} - min={1} - label="Adults" - desc="Ages 13 or above" - /> - handleChangeData(value, "guestChildren")} - max={4} - label="Children" - desc="Ages 2–12" - /> - - handleChangeData(value, "guestInfants")} - max={4} - label="Infants" - desc="Ages 0–2" - /> - - - - )} -
- ); -}; - -export default GuestsInput; diff --git a/src/app/(listing-detail)/listing-stay-detail/StayDatesRangeInput.tsx b/src/app/(listing-detail)/listing-stay-detail/StayDatesRangeInput.tsx deleted file mode 100644 index 7b00e12..0000000 --- a/src/app/(listing-detail)/listing-stay-detail/StayDatesRangeInput.tsx +++ /dev/null @@ -1,109 +0,0 @@ -"use client"; - -import React, { Fragment, useState, FC } from "react"; -import { Popover, Transition } from "@headlessui/react"; -import { CalendarIcon } from "@heroicons/react/24/outline"; -import DatePickerCustomHeaderTwoMonth from "@/components/DatePickerCustomHeaderTwoMonth"; -import DatePickerCustomDay from "@/components/DatePickerCustomDay"; -import DatePicker from "react-datepicker"; -import ClearDataButton from "@/app/(client-components)/(HeroSearchForm)/ClearDataButton"; - -export interface StayDatesRangeInputProps { - className?: string; -} - -const StayDatesRangeInput: FC = ({ - className = "flex-1", -}) => { - const [startDate, setStartDate] = useState( - new Date("2023/02/06") - ); - const [endDate, setEndDate] = useState(new Date("2023/02/23")); - // - - const onChangeDate = (dates: [Date | null, Date | null]) => { - const [start, end] = dates; - setStartDate(start); - setEndDate(end); - }; - - const renderInput = () => { - return ( - <> -
- -
-
- - {startDate?.toLocaleDateString("en-US", { - month: "short", - day: "2-digit", - }) || "Add dates"} - {endDate - ? " - " + - endDate?.toLocaleDateString("en-US", { - month: "short", - day: "2-digit", - }) - : ""} - - - {"Check in - Check out"} - -
- - ); - }; - - return ( - - {({ open }) => ( - <> - - {renderInput()} - {startDate && open && ( - onChangeDate([null, null])} /> - )} - - - - -
- ( - - )} - renderDayContents={(day, date) => ( - - )} - /> -
-
-
- - )} -
- ); -}; - -export default StayDatesRangeInput; diff --git a/src/app/(listing-detail)/listing-stay-detail/constant.ts b/src/app/(listing-detail)/listing-stay-detail/constant.ts deleted file mode 100644 index 90af950..0000000 --- a/src/app/(listing-detail)/listing-stay-detail/constant.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { ListingGalleryImage } from "@/components/listing-image-gallery/utils/types"; - -export const PHOTOS: string[] = [ - "https://images.pexels.com/photos/6129967/pexels-photo-6129967.jpeg?auto=compress&cs=tinysrgb&dpr=3&h=750&w=1260", - "https://images.pexels.com/photos/7163619/pexels-photo-7163619.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260", - "https://images.pexels.com/photos/6527036/pexels-photo-6527036.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260", - "https://images.pexels.com/photos/6969831/pexels-photo-6969831.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260", - "https://images.pexels.com/photos/6438752/pexels-photo-6438752.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260", - "https://images.pexels.com/photos/1320686/pexels-photo-1320686.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260", - "https://images.pexels.com/photos/261394/pexels-photo-261394.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260", - "https://images.pexels.com/photos/2861361/pexels-photo-2861361.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260", - "https://images.pexels.com/photos/2677398/pexels-photo-2677398.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260", - "https://images.pexels.com/photos/1365425/pexels-photo-1365425.jpeg?auto=compress&cs=tinysrgb&w=1600", - "https://images.pexels.com/photos/914128/pexels-photo-914128.jpeg?auto=compress&cs=tinysrgb&w=1600", - "https://images.pexels.com/photos/840667/pexels-photo-840667.jpeg?auto=compress&cs=tinysrgb&w=1600", - "https://images.pexels.com/photos/732632/pexels-photo-732632.jpeg?auto=compress&cs=tinysrgb&w=1600", - "https://images.pexels.com/photos/450062/pexels-photo-450062.jpeg?auto=compress&cs=tinysrgb&w=1600", - "https://images.pexels.com/photos/917510/pexels-photo-917510.jpeg?auto=compress&cs=tinysrgb&w=1600", - "https://images.pexels.com/photos/1194233/pexels-photo-1194233.jpeg?auto=compress&cs=tinysrgb&w=1600", - "https://images.pexels.com/photos/236973/pexels-photo-236973.jpeg?auto=compress&cs=tinysrgb&w=1600", - "https://images.pexels.com/photos/1392099/pexels-photo-1392099.jpeg?auto=compress&cs=tinysrgb&w=1600", - "https://images.pexels.com/photos/547116/pexels-photo-547116.jpeg?auto=compress&cs=tinysrgb&w=1600", - "https://images.pexels.com/photos/1002272/pexels-photo-1002272.jpeg?auto=compress&cs=tinysrgb&w=1600", - "https://images.pexels.com/photos/917511/pexels-photo-917511.jpeg?auto=compress&cs=tinysrgb&w=1600", - "https://images.pexels.com/photos/771079/pexels-photo-771079.jpeg?auto=compress&cs=tinysrgb&w=1600", - "https://images.pexels.com/photos/13461077/pexels-photo-13461077.jpeg?auto=compress&cs=tinysrgb&w=1600&lazy=load", - "https://images.pexels.com/photos/9074921/pexels-photo-9074921.jpeg?auto=compress&cs=tinysrgb&w=1600&lazy=load", - "https://images.pexels.com/photos/9336042/pexels-photo-9336042.jpeg?auto=compress&cs=tinysrgb&w=1600&lazy=load", - "https://images.pexels.com/photos/5418318/pexels-photo-5418318.jpeg?auto=compress&cs=tinysrgb&w=1600&lazy=load", - "https://images.pexels.com/photos/4815278/pexels-photo-4815278.jpeg?auto=compress&cs=tinysrgb&w=1600&lazy=load", - "https://images.pexels.com/photos/1365425/pexels-photo-1365425.jpeg?auto=compress&cs=tinysrgb&w=1600", -]; - -export const Amenities_demos = [ - { name: "la-key", icon: "la-key" }, - { name: "la-luggage-cart", icon: "la-luggage-cart" }, - { name: "la-shower", icon: "la-shower" }, - { name: "la-smoking", icon: "la-smoking" }, - { name: "la-snowflake", icon: "la-snowflake" }, - { name: "la-spa", icon: "la-spa" }, - { name: "la-suitcase", icon: "la-suitcase" }, - { name: "la-suitcase-rolling", icon: "la-suitcase-rolling" }, - { name: "la-swimmer", icon: "la-swimmer" }, - { name: "la-swimming-pool", icon: "la-swimming-pool" }, - { name: "la-tv", icon: "la-tv" }, - { name: "la-umbrella-beach", icon: "la-umbrella-beach" }, - { name: "la-utensils", icon: "la-utensils" }, - { name: "la-wheelchair", icon: "la-wheelchair" }, - { name: "la-wifi", icon: "la-wifi" }, - { name: "la-baby-carriage", icon: "la-baby-carriage" }, - { name: "la-bath", icon: "la-bath" }, - { name: "la-bed", icon: "la-bed" }, - { name: "la-briefcase", icon: "la-briefcase" }, - { name: "la-car", icon: "la-car" }, - { name: "la-cocktail", icon: "la-cocktail" }, - { name: "la-coffee", icon: "la-coffee" }, - { name: "la-concierge-bell", icon: "la-concierge-bell" }, - { name: "la-dice", icon: "la-dice" }, - { name: "la-dumbbell", icon: "la-dumbbell" }, - { name: "la-hot-tub", icon: "la-hot-tub" }, - { name: "la-infinity", icon: "la-infinity" }, -]; - -export const imageGallery: ListingGalleryImage[] = [...PHOTOS].map( - (item, index): ListingGalleryImage => { - return { - id: index, - url: item, - }; - } -); diff --git a/src/app/(listing-detail)/listing-stay-detail/page.tsx b/src/app/(listing-detail)/listing-stay-detail/page.tsx deleted file mode 100644 index 11ca741..0000000 --- a/src/app/(listing-detail)/listing-stay-detail/page.tsx +++ /dev/null @@ -1,637 +0,0 @@ -"use client"; - -import React, { FC, Fragment, useState } from "react"; -import { Dialog, Transition } from "@headlessui/react"; -import { ArrowRightIcon, Squares2X2Icon } from "@heroicons/react/24/outline"; -import CommentListing from "@/components/CommentListing"; -import FiveStartIconForRate from "@/components/FiveStartIconForRate"; -import StartRating from "@/components/StartRating"; -import Avatar from "@/shared/Avatar"; -import Badge from "@/shared/Badge"; -import ButtonCircle from "@/shared/ButtonCircle"; -import ButtonPrimary from "@/shared/ButtonPrimary"; -import ButtonSecondary from "@/shared/ButtonSecondary"; -import ButtonClose from "@/shared/ButtonClose"; -import Input from "@/shared/Input"; -import LikeSaveBtns from "@/components/LikeSaveBtns"; -import Image from "next/image"; -import { usePathname, useRouter } from "next/navigation"; -import { Amenities_demos, PHOTOS } from "./constant"; -import StayDatesRangeInput from "./StayDatesRangeInput"; -import GuestsInput from "./GuestsInput"; -import SectionDateRange from "../SectionDateRange"; -import { Route } from "next"; - -export interface ListingStayDetailPageProps {} - -const ListingStayDetailPage: FC = ({}) => { - // - - let [isOpenModalAmenities, setIsOpenModalAmenities] = useState(false); - - const thisPathname = usePathname(); - const router = useRouter(); - - function closeModalAmenities() { - setIsOpenModalAmenities(false); - } - - function openModalAmenities() { - setIsOpenModalAmenities(true); - } - - const handleOpenModalImageGallery = () => { - router.push(`${thisPathname}/?modal=PHOTO_TOUR_SCROLLABLE` as Route); - }; - - const renderSection1 = () => { - return ( -
- {/* 1 */} -
- - -
- - {/* 2 */} -

- Beach House in Collingwood -

- - {/* 3 */} -
- - · - - - Tokyo, Jappan - -
- - {/* 4 */} -
- - - Hosted by{" "} - - Kevin Francis - - -
- - {/* 5 */} -
- - {/* 6 */} -
-
- - - 6 guests - -
-
- - - 6 beds - -
-
- - - 3 baths - -
-
- - - 2 bedrooms - -
-
-
- ); - }; - - const renderSection2 = () => { - return ( -
-

Stay information

-
-
- - Providing lake views, The Symphony 9 Tam Coc in Ninh Binh provides - accommodation, an outdoor swimming pool, a bar, a shared lounge, a - garden and barbecue facilities. Complimentary WiFi is provided. - -
-
- - There is a private bathroom with bidet in all units, along with a - hairdryer and free toiletries. - -

- - The Symphony 9 Tam Coc offers a terrace. Both a bicycle rental - service and a car rental service are available at the accommodation, - while cycling can be enjoyed nearby. - -
-
- ); - }; - - const renderSection3 = () => { - return ( -
-
-

Amenities

- - {` About the property's amenities and services`} - -
-
- {/* 6 */} -
- {Amenities_demos.filter((_, i) => i < 12).map((item) => ( -
- - {item.name} -
- ))} -
- - {/* ----- */} -
-
- - View more 20 amenities - -
- {renderMotalAmenities()} -
- ); - }; - - const renderMotalAmenities = () => { - return ( - - -
- - - - - {/* This element is to trick the browser into centering the modal contents. */} - - -
-
-
-

- Amenities -

- - - -
-
- {Amenities_demos.filter((_, i) => i < 1212).map((item) => ( -
- - {item.name} -
- ))} -
-
-
-
-
-
-
- ); - }; - - const renderSection4 = () => { - return ( -
- {/* HEADING */} -
-

Room Rates

- - Prices may increase on weekends or holidays - -
-
- {/* CONTENT */} -
-
-
- Monday - Thursday - $199 -
-
- Monday - Thursday - $199 -
-
- Friday - Sunday - $219 -
-
- Rent by month - -8.34 % -
-
- Minimum number of nights - 1 night -
-
- Max number of nights - 90 nights -
-
-
-
- ); - }; - - const renderSection5 = () => { - return ( -
- {/* HEADING */} -

Host Information

-
- - {/* host */} -
- -
- - Kevin Francis - -
- - · - 12 places -
-
-
- - {/* desc */} - - Providing lake views, The Symphony 9 Tam Coc in Ninh Binh provides - accommodation, an outdoor swimming pool, a bar, a shared lounge, a - garden and barbecue facilities... - - - {/* info */} -
-
- - - - Joined in March 2016 -
-
- - - - Response rate - 100% -
-
- - - - - Fast response - within a few hours -
-
- - {/* == */} -
-
- See host profile -
-
- ); - }; - - const renderSection6 = () => { - return ( -
- {/* HEADING */} -

Reviews (23 reviews)

-
- - {/* Content */} -
- -
- - - - -
-
- - {/* comment */} -
- - - - -
- View more 20 reviews -
-
-
- ); - }; - - const renderSection7 = () => { - return ( -
- {/* HEADING */} -
-

Location

- - San Diego, CA, United States of America (SAN-San Diego Intl.) - -
-
- - {/* MAP */} -
-
- -
-
-
- ); - }; - - const renderSection8 = () => { - return ( -
- {/* HEADING */} -

Things to know

-
- - {/* CONTENT */} -
-

Cancellation policy

- - Refund 50% of the booking value when customers cancel the room - within 48 hours after successful booking and 14 days before the - check-in time.
- Then, cancel the room 14 days before the check-in time, get a 50% - refund of the total amount paid (minus the service fee). -
-
-
- - {/* CONTENT */} -
-

Check-in time

-
-
- Check-in - 08:00 am - 12:00 am -
-
- Check-out - 02:00 pm - 04:00 pm -
-
-
-
- - {/* CONTENT */} -
-

Special Note

-
-
    -
  • - Ban and I will work together to keep the landscape and - environment green and clean by not littering, not using - stimulants and respecting people around. -
  • -
  • Do not sing karaoke past 11:30
  • -
-
-
-
- ); - }; - - const renderSidebar = () => { - return ( -
- {/* PRICE */} -
- - $119 - - /night - - - -
- - {/* FORM */} -
- -
- - - - {/* SUM */} -
-
- $119 x 3 night - $357 -
-
- Service charge - $0 -
-
-
- Total - $199 -
-
- - {/* SUBMIT */} - Reserve -
- ); - }; - - return ( -
- {/* HEADER */} -
-
-
- -
-
- {PHOTOS.filter((_, i) => i >= 1 && i < 5).map((item, index) => ( -
= 3 ? "hidden sm:block" : "" - }`} - > -
- -
- - {/* OVERLAY */} -
-
- ))} - - -
-
- - {/* MAIN */} -
- {/* CONTENT */} -
- {renderSection1()} - {renderSection2()} - {renderSection3()} - {renderSection4()} - - {renderSection5()} - {renderSection6()} - {renderSection7()} - {renderSection8()} -
- - {/* SIDEBAR */} -
-
{renderSidebar()}
-
-
-
- ); -}; - -export default ListingStayDetailPage; diff --git a/src/app/(real-estate-listings)/layout.tsx b/src/app/(real-estate-listings)/layout.tsx index cde549a..0dd8cf0 100644 --- a/src/app/(real-estate-listings)/layout.tsx +++ b/src/app/(real-estate-listings)/layout.tsx @@ -3,14 +3,10 @@ import SectionGridAuthorBox from "@/components/SectionGridAuthorBox"; import SectionSliderNewCategories from "@/components/SectionSliderNewCategories"; import SectionSubscribe2 from "@/components/SectionSubscribe2"; import React, { ReactNode } from "react"; -import SectionHero2ArchivePage from "../(server-components)/SectionHero2ArchivePage"; const Layout = ({ children }: { children: ReactNode }) => { return (
-
- -
{children} diff --git a/src/app/(server-components)/SectionHero2ArchivePage.tsx b/src/app/(server-components)/SectionHero2ArchivePage.tsx deleted file mode 100644 index cee0cb4..0000000 --- a/src/app/(server-components)/SectionHero2ArchivePage.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import React, { FC } from "react"; -import imagePng from "@/images/hero-right-3.png"; -import Image from "next/image"; -import HeroRealEstateSearchForm from "../(client-components)/(HeroSearchForm)/(real-estate-search-form)/HeroRealEstateSearchForm"; - -export interface SectionHero2ArchivePageProps { - className?: string; -} - -const SectionHero2ArchivePage: FC = ({ - className = "", -}) => { - return ( -
-
- hero -
-
-
-
-
-

- Tokyo, Jappan -

-
- - Jappan - - - 112 properties -
-
-
-
- -
-
-
- ); -}; - -export default SectionHero2ArchivePage; diff --git a/src/app/add-listing/[[...stepIndex]]/PageAddListing1.tsx b/src/app/add-listing/[[...stepIndex]]/PageAddListing1.tsx index f832690..ee9df59 100644 --- a/src/app/add-listing/[[...stepIndex]]/PageAddListing1.tsx +++ b/src/app/add-listing/[[...stepIndex]]/PageAddListing1.tsx @@ -1,17 +1,16 @@ import React, { FC, useEffect, useState } from "react"; import Input from "@/shared/Input"; -import Select from "@/shared/Select"; import FormItem from "../FormItem"; import { IoPersonAddOutline } from "react-icons/io5"; import getImageURL from "@/components/api/getImageURL"; import ConfirmModal from "../../../shared/popUp"; import axiosInstance from "@/components/api/axios"; -import PassengerTable from "@/app/(account-pages)/passengers-list/PassengerTable"; import { useUserContext } from "@/components/contexts/userContext"; import { useRouter } from "next/navigation"; export interface PageAddListing1Props { + ageLabel : string ; Passenger: any; setNewPassenger: (passenger: any) => void; errors: any; @@ -22,26 +21,25 @@ export interface PageAddListing1Props { } const PageAddListing1: FC = ({ + ageLabel , Passenger, setNewPassenger, errors, passengerID, setPassengerID, selectedPassenger, - setSelectedPassenger, // Receive the function to reset selectedPassenger + setSelectedPassenger, }) => { - const router = useRouter() - - const { fullName, date, number, passport } = Passenger; - - const { user } = useUserContext() - + const router = useRouter(); + const { user } = useUserContext(); const [savedPassengers, setSavedPassengers] = useState([]); const [loading, setLoading] = useState(false); + const [dateError , setDateError] = useState(false) + const [passengerAgeLable , setPassengerAgeLAble] = useState(ageLabel) - if(!Object.keys(user).length){ - router.replace("/signup") + if (!Object.keys(user).length) { + router.replace("/signup"); } useEffect(() => { @@ -59,135 +57,208 @@ const PageAddListing1: FC = ({ console.error(error); }); }, []); - console.log(savedPassengers); const handleFileChange = async (e: React.ChangeEvent) => { - setLoading(true) + setLoading(true); const file = e.target.files?.[0]; if (file) { const uploadedFile = await getImageURL(file); - setNewPassenger((prev: any) => ({ ...prev, passport_image: uploadedFile.url })); - setLoading(false) + setNewPassenger((prev: any) => ({ + ...prev, + passport_image: uploadedFile.url, + })); + setLoading(false); } }; - const AddPassengerId = (passenger: {id : string | number}) => { + const AddPassengerId = (passenger: { id: string | number }) => { setSelectedPassenger(passenger); console.log(passenger.id); - setPassengerID((prev : any) => { + setPassengerID((prev: any) => { if (!Array.isArray(prev)) { prev = []; } - const exists = prev.some((p: { passenger_id: any; }) => p.passenger_id === passenger.id); + const exists = prev.some( + (p: { passenger_id: any }) => p.passenger_id === passenger.id + ); if (exists) { return prev; } return [...prev, { passenger_id: passenger.id }]; }); }; + const INFANT_AGE = 2; + const CHILD_AGE = 12; + + - return ( - !selectedPassenger ? ( - <> -

Choosing listing categories

-
- {/* FORM */} - - {/* Adjust icon size */} -

Add from passenger list

-
- } - > - {(closeModal: () => void) => ( -
    - {savedPassengers?.map((item : {fullname : string , id : string | number}, index) => ( -
  • { AddPassengerId(item); closeModal(); }} + const calculateAgeCategory = (birthdate: string): string => { + const birthDate = new Date(birthdate); + const today = new Date(); + let age = today.getFullYear() - birthDate.getFullYear(); + const monthDifference = today.getMonth() - birthDate.getMonth(); + + if ( + monthDifference < 0 || + (monthDifference === 0 && today.getDate() < birthDate.getDate()) + ) { + age--; + } + + if (age <= INFANT_AGE) { + setPassengerAgeLAble("Infant") + return "Infant"; + } else if (age <= CHILD_AGE) { + setPassengerAgeLAble("Child") + return "Child"; + } else { + setPassengerAgeLAble("Adult") + return "Adult"; + } + }; + + // Handle change for birthdate and validate against ageLabel + const handleBirthdateChange = (e: React.ChangeEvent) => { + const newBirthdate = e.target.value; + const derivedAgeCategory = calculateAgeCategory(newBirthdate); + const isDateMatchingAgeLabel = derivedAgeCategory === ageLabel; + + setDateError(!isDateMatchingAgeLabel); + + setNewPassenger((prev: any) => ({ + ...prev, + birthdate: newBirthdate, + })); + }; + + return !selectedPassenger ? ( + <> +

    Choosing listing categories

    +
    + + {/* FORM */} + + +

    Add from passenger list

    +
+ } + > + {(closeModal: () => void) => ( +
    + {savedPassengers?.map( + (item: { fullname: string; id: string | number }, index) => ( +
  • { + AddPassengerId(item); + closeModal(); + }} key={index} className={`cursor-pointer rounded-md p-3 hover:bg-bronze bg-white border-2 dark:bg-gray-700 text-neutral-900 dark:text-white`} >

    {item.fullname}

  • - ))} -
+ ) + )} + + )} + + +
+ {/* Full Name Field */} + + + setNewPassenger((prev: any) => ({ + ...prev, + fullname: e.target.value, + })) + } + value={Passenger.fullname || ""} + placeholder="Full Name" + /> + {errors.fullname && ( +

{errors.fullname}

)} - +
-
- {/* ITEM */} + {/* Passport Number Field */} + + + setNewPassenger((prev: any) => ({ + ...prev, + passport_number: e.target.value, + })) + } + value={Passenger.passport_number || ""} + placeholder="Passport Number" + /> + {errors.passport_number && ( +

{errors.passport_number}

+ )} +
- - - setNewPassenger((prev: any) => ({ ...prev, fullname: e.target.value })) - } - value={fullName} - placeholder="Full Name" - /> - {errors.fullName && ( -

{errors.fullName}

- )} -
- - - setNewPassenger((prev: any) => ({ ...prev, passport_number: e.target.value })) - } - value={passport} - placeholder="Passport Number" - /> - {errors.passport && ( -

{errors.passport}

- )} -
- + {/* Date of Birth Field */} + +
- setNewPassenger((prev: any) => ({ ...prev, birthdate: e.target.value })) - } + value={Passenger.birthdate || ""} + onChange={handleBirthdateChange} placeholder="Date of Birth" /> - {errors.date && ( -

{errors.date}

- )} - - - - setNewPassenger((prev: any) => ({ ...prev, phone_number: e.target.value })) - } - placeholder="Phone Number" - /> - {errors.number && ( -

{errors.number}

+ {ageLabel && ( + + {passengerAgeLable} + )} -
- - - {loading &&

loading ...

} - {errors.image && ( -

{errors.image}

- )} -
-
- - ) : ( -

{selectedPassenger.fullname}

- ) +
+ {errors.birthdate && ( +

{errors.birthdate}

+ )} + {/* {dateError && ( +

Date does not match the age category

+ )} */} + + + {/* Phone Number Field */} + + + setNewPassenger((prev: any) => ({ + ...prev, + phone_number: e.target.value, + })) + } + placeholder="Phone Number" + /> + {errors.phone_number && ( +

{errors.phone_number}

+ )} +
+ + {/* Passport Image Field */} + + + {loading &&

loading ...

} + {errors.passport_image && ( +

{errors.passport_image}

+ )} +
+
+ + ) : ( +

{selectedPassenger.fullname}

); }; + export default PageAddListing1; diff --git a/src/app/add-listing/[[...stepIndex]]/page.tsx b/src/app/add-listing/[[...stepIndex]]/page.tsx index c1b59f5..710b8f3 100644 --- a/src/app/add-listing/[[...stepIndex]]/page.tsx +++ b/src/app/add-listing/[[...stepIndex]]/page.tsx @@ -1,4 +1,4 @@ -"use client" +"use client"; import React, { useContext, useState, useEffect } from "react"; import { FC } from "react"; import ButtonPrimary from "@/shared/ButtonPrimary"; @@ -9,6 +9,7 @@ import { useRouter } from "next/navigation"; import axiosInstance from "@/components/api/axios"; import { useUserContext } from "@/components/contexts/userContext"; import { toast } from "react-toastify"; +import ButtonSecondary from "@/shared/ButtonSecondary"; export interface CommonLayoutProps { children: React.ReactNode; @@ -36,12 +37,23 @@ const CommonLayout: FC = ({ params }) => { const [redirecting, setRedirecting] = useState(false); const tourID = params.stepIndex[0]; - const totalPassengers = useContext(Context).passengers; + const context = useContext(Context); + if (!context) { + throw new Error("Context is not defined"); + } + const { guestAdults, guestChildren, guestInfants } = context.passengers; + + const totalPassengers = guestAdults + guestChildren + guestInfants + console.log(totalPassengers); + + const nextHref = () => setIndex((prev) => prev + 1); - const backtHref = () => (index > 1 ? setIndex((prev) => prev - 1) : index); + const backHref = () => setIndex((prev) => prev - 1); const nextBtnText = index === totalPassengers ? "Save Passengers" : "Continue"; + const ageLabel = index > guestAdults ? index > guestAdults + guestChildren ?"Infant" : "Child" : "Adult" + useEffect(() => { Object.values(errors).forEach((error) => { toast.error(error, { @@ -50,7 +62,8 @@ const CommonLayout: FC = ({ params }) => { }); }); }, [errors]); - + + console.log(index , guestAdults); const sendPassengers = async () => { const dataToSend = { tour_id: tourID, @@ -60,7 +73,6 @@ const CommonLayout: FC = ({ params }) => { }, }; - console.log("Data being sent:", dataToSend); try { const response = await axiosInstance.post( @@ -76,7 +88,7 @@ const CommonLayout: FC = ({ params }) => { console.log(response); setRedirecting(true); } catch (error) { - backtHref(); + backHref(); console.error("Error submitting passengers:", error); } }; @@ -110,8 +122,19 @@ const CommonLayout: FC = ({ params }) => { return; } - // Add new passenger - setPassengers((prevPassengers) => [...prevPassengers, newPassenger]); + if (index <= passengers.length) { + // Update existing passenger + setPassengers((prevPassengers) => { + const updatedPassengers = [...prevPassengers]; + updatedPassengers[index - 1] = newPassenger; + return updatedPassengers; + }); + } else { + // Add new passenger + setPassengers((prevPassengers) => [...prevPassengers, newPassenger]); + } + + // Reset newPassenger setNewPassenger({ fullname: "", passport_number: "", @@ -124,23 +147,47 @@ const CommonLayout: FC = ({ params }) => { nextHref(); }; + const backHandler = () => { + if (index > 1) { + backHref(); + if (selectedPassenger) { + // Remove the last selected passenger ID + setPassengerID((prev) => prev.slice(0, -1)); + setSelectedPassenger(null); + } else { + // Set newPassenger to the data of the last passenger + const lastPassenger = passengers[index - 2]; // Adjust index for zero-based array + setNewPassenger(lastPassenger); + + // Remove the last passenger from the passengers array + setPassengers((prevPassengers) => prevPassengers.slice(0, -1)); + } + } + }; + if (redirecting) { return null; } return ( -
+
{index}{" "} - / {totalPassengers} + / {totalPassengers} + + +   {ageLabel}
{/* Passenger Form */}
= ({ params }) => { />
-
+
+ Back {nextBtnText}
diff --git a/src/app/blog/SectionMagazine5.tsx b/src/app/blog/SectionMagazine5.tsx index 791f04c..dc681b4 100644 --- a/src/app/blog/SectionMagazine5.tsx +++ b/src/app/blog/SectionMagazine5.tsx @@ -1,7 +1,6 @@ "use client" import React, { FC, useEffect, useState } from "react"; -import { PostDataType } from "@/data/types"; import Card12 from "./Card12"; import Card13 from "./Card13"; import axiosInstance from "@/components/api/axios"; @@ -26,7 +25,6 @@ const SectionMagazine5 = () => {
-

{t("welcome")}

{posts[0] && }
{posts diff --git a/src/app/custom-trip/page.tsx b/src/app/custom-trip/page.tsx index 54eebab..90b0aae 100644 --- a/src/app/custom-trip/page.tsx +++ b/src/app/custom-trip/page.tsx @@ -9,6 +9,7 @@ import Input from "@/shared/Input"; import { useRouter } from "next/navigation"; import { useUserContext } from "@/components/contexts/userContext"; import { toast } from "react-toastify"; +import NcInputNumber from "@/components/NcInputNumber"; interface City { name: string; @@ -26,15 +27,12 @@ const CommonLayout: FC = () => { const { user } = useUserContext(); const router = useRouter(); - useEffect(() => { - if (!Object.keys(user).length) { - router.replace("/signup"); - } - }, [user, router]); - const [countries, setCountries] = useState([]); const [startCity, setStartCity] = useState(""); const [startDate, setStartDate] = useState(""); + const [guestAdultsInputValue, setGuestAdultsInputValue] = useState(1); + const [guestChildrenInputValue, setGuestChildrenInputValue] = useState(0); + const [guestInfantsInputValue, setGuestInfantsInputValue] = useState(0); const [passengers, setPassengers] = useState(1); const [transport, setTransport] = useState([]); const [hotel, setHotel] = useState([]); @@ -224,6 +222,22 @@ const CommonLayout: FC = () => { validateForm(); }; + const handleChangeData = (value: number, type: string) => { + if (type === "guestAdults") { + setGuestAdultsInputValue(value); + } else if (type === "guestChildren") { + setGuestChildrenInputValue(value); + } else if (type === "guestInfants") { + setGuestInfantsInputValue(value); + } + }; + + useEffect(() => { + setPassengers( + guestAdultsInputValue + guestChildrenInputValue + guestInfantsInputValue + ); + }, [guestAdultsInputValue, guestChildrenInputValue, guestInfantsInputValue]); + const submitTour = async () => { const formData = { destinations: destinations.map((destination, index) => ({ @@ -241,25 +255,28 @@ const CommonLayout: FC = () => { number_passenger: `${passengers}`, start_date: startDate.replace(/-/g, "/"), }, - ...destinations.reduce<{ [key: number]: any }>((acc, destination, index) => { - acc[index + 2] = { - title: `${stringifyNumber(index + 1)} Destination`, - city: `${destination.endCity - .split("/")[0] - .trim()}-${destination.endCity.split("/")[1].trim()} `, - transportation: destination.transport, - hotel: destination.hotel, - duration: `${destination.duration} day`, - finish_date: destination.finishDate.replace(/-/g, "/"), - start_date: startDate.replace(/-/g, "/"), - }; - return acc; - }, {}), + ...destinations.reduce<{ [key: number]: any }>( + (acc, destination, index) => { + acc[index + 2] = { + title: `${stringifyNumber(index + 1)} Destination`, + city: `${destination.endCity + .split("/")[0] + .trim()}-${destination.endCity.split("/")[1].trim()} `, + transportation: destination.transport, + hotel: destination.hotel, + duration: `${destination.duration} day`, + finish_date: destination.finishDate.replace(/-/g, "/"), + start_date: startDate.replace(/-/g, "/"), + }; + return acc; + }, + {} + ), summary: { cost_estimate: estimatedCost.toString(), - journery_schedule: `${startDate.replace(/-/g, "/")} To ${destinations[ - destinations.length - 1 - ]?.finishDate.replace(/-/g, "/")} Day ${destinations.length}`, + journery_schedule: `${startDate.replace(/-/g, "/")} To ${ + destinations[destinations.length - 1]?.finishDate.replace(/-/g, "/") + } Day ${destinations.length}`, }, }), }; @@ -313,25 +330,45 @@ const CommonLayout: FC = () => { )} -
- + setStartDate(e.target.value)} /> - - - setPassengers(Math.max(1, Number(e.target.value))) - } - min="1" - /> + +
+ + handleChangeData(value, "guestAdults")} + max={20} + label="Adults" + desc="Ages 13 or above" + /> + + handleChangeData(value, "guestChildren") + } + max={20} + label="Children" + desc="Ages 2–12" + /> + + handleChangeData(value, "guestInfants")} + max={20} + label="Infants" + desc="Ages 0–2" + /> +
-
diff --git a/src/app/tours/[slug]/GuestsInput.tsx b/src/app/tours/[slug]/GuestsInput.tsx index a8265dd..53e2dfe 100644 --- a/src/app/tours/[slug]/GuestsInput.tsx +++ b/src/app/tours/[slug]/GuestsInput.tsx @@ -1,33 +1,62 @@ "use client"; -import React, { Fragment, FC, useState, useContext } from "react"; +import React, { Fragment, FC, useState, useContext, useEffect } from "react"; import { Popover, Transition } from "@headlessui/react"; import NcInputNumber from "@/components/NcInputNumber"; import { UserPlusIcon } from "@heroicons/react/24/outline"; import ClearDataButton from "@/app/(client-components)/(HeroSearchForm)/ClearDataButton"; import { GuestsObject } from "@/app/(client-components)/type"; -import { Context, useToursContext } from "@/components/contexts/tourDetails"; +import { useToursContext } from "@/components/contexts/tourDetails"; export interface GuestsInputProps { className?: string; + footer?: boolean; } -const GuestsInput: FC = ({ className = "flex-1" }) => { - const { setPassengers, passengers } = useToursContext(); +const GuestsInput: FC = ({ + className = "flex-1", + footer = false, +}) => { + const { passengers, setPassengers } = useToursContext(); - const [guestAdultsInputValue, setGuestAdultsInputValue] = - useState(passengers); + const [guestAdultsInputValue, setGuestAdultsInputValue] = useState(0); + const [guestChildrenInputValue, setGuestChildrenInputValue] = useState(0); + const [guestInfantsInputValue, setGuestInfantsInputValue] = useState(0); - const handleChangeData = (value: number) => { - let newValue = { + const handleChangeData = (value: number, type: keyof GuestsObject) => { + const newValue = { guestAdults: guestAdultsInputValue, + guestChildren: guestChildrenInputValue, + guestInfants: guestInfantsInputValue, }; - setGuestAdultsInputValue(value); - newValue.guestAdults = value; - setPassengers(value); + + if (type === "guestAdults") setGuestAdultsInputValue(value); + else if (type === "guestChildren") setGuestChildrenInputValue(value); + else if (type === "guestInfants") setGuestInfantsInputValue(value); + + setPassengers({ + guestAdults: newValue.guestAdults, + guestChildren: newValue.guestChildren, + guestInfants: newValue.guestInfants, + }); }; - const totalGuests = guestAdultsInputValue; + useEffect(() => { + setGuestAdultsInputValue(passengers.guestAdults); + setGuestChildrenInputValue(passengers.guestChildren); + setGuestInfantsInputValue(passengers.guestInfants); + }, []); + + useEffect(() => { + setPassengers({ + guestAdults: guestAdultsInputValue, + guestChildren: guestChildrenInputValue, + guestInfants: guestInfantsInputValue, + }); + }, [guestAdultsInputValue, guestChildrenInputValue, guestInfantsInputValue]); + + const totalGuests = + guestAdultsInputValue + guestChildrenInputValue + guestInfantsInputValue; return ( @@ -57,7 +86,13 @@ const GuestsInput: FC = ({ className = "flex-1" }) => { { setGuestAdultsInputValue(0); - setPassengers(0); + setGuestChildrenInputValue(0); + setGuestInfantsInputValue(0); + setPassengers({ + guestAdults: 0, + guestChildren: 0, + guestInfants: 0, + }); }} /> )} @@ -73,16 +108,38 @@ const GuestsInput: FC = ({ className = "flex-1" }) => { leaveFrom="opacity-100 translate-y-0" leaveTo="opacity-0 translate-y-1" > - + handleChangeData(value)} + onChange={(value) => handleChangeData(value, "guestAdults")} max={10} min={1} - label="Passsengers" + label="Adults" desc="Ages 13 or above" /> + handleChangeData(value, "guestChildren")} + max={4} + min={0} + label="Children" + desc="Ages 2–12" + /> + handleChangeData(value, "guestInfants")} + max={4} + min={0} + label="Infants" + desc="Ages 0–2" + /> diff --git a/src/app/tours/[slug]/page.tsx b/src/app/tours/[slug]/page.tsx index 3575835..8377fee 100644 --- a/src/app/tours/[slug]/page.tsx +++ b/src/app/tours/[slug]/page.tsx @@ -9,7 +9,7 @@ import { useToursContext } from "@/components/contexts/tourDetails"; import ConfirmModal from "@/shared/popUp"; import StayDatesRangeInput from "./StayDatesRangeInput"; import GuestsInput from "./GuestsInput"; -import MobileFooterSticky from "@/app/(listing-detail)/(components)/MobileFooterSticky"; +import MobileFooterSticky from "@/components/MobileFooterSticky"; import ButtonPrimary from "@/shared/ButtonPrimary"; import StartRating from "@/components/StartRating"; @@ -47,6 +47,8 @@ const ListingStayDetailPage: FC = () => { const { slug } = useParams(); // Assuming `slug` contains the tour ID const id = slug?.match(/-?(\d+)$/)?.[1] || null; + const totalGuests = passengers.guestAdults + passengers.guestChildren + passengers.guestInfants; + // Fetch details and itinerary on component mount useEffect(() => { @@ -120,7 +122,7 @@ const ListingStayDetailPage: FC = () => { const renderSidebar = () => { const total = details?.final_price && passengers - ? (Number(details?.final_price) * passengers).toLocaleString("en-US", { style: "currency", currency: "USD" }) + ? (Number(details?.final_price) * totalGuests).toLocaleString("en-US", { style: "currency", currency: "USD" }) : 0; return ( @@ -217,7 +219,7 @@ const ListingStayDetailPage: FC = () => { {/* Mobile Footer */} - +
); }; diff --git a/src/app/tours/layout.tsx b/src/app/tours/layout.tsx index 552f006..ec3d828 100644 --- a/src/app/tours/layout.tsx +++ b/src/app/tours/layout.tsx @@ -6,9 +6,6 @@ import SectionSliderNewCategories from "@/components/SectionSliderNewCategories" import SectionSubscribe2 from "@/components/SectionSubscribe2"; import { usePathname, useRouter, useSearchParams } from "next/navigation"; import React, { ReactNode } from "react"; -import MobileFooterSticky from "../(listing-detail)/(components)/MobileFooterSticky"; -import { imageGallery as listingStayImageGallery } from "./[slug]/constant"; -import { Route } from "next"; const DetailtLayout = ({ children }: { children: ReactNode }) => { const router = useRouter(); @@ -16,33 +13,11 @@ const DetailtLayout = ({ children }: { children: ReactNode }) => { const searchParams = useSearchParams(); const modal = searchParams?.get("modal"); - const handleCloseModalImageGallery = () => { - let params = new URLSearchParams(document.location.search); - params.delete("modal"); - router.push(`${thisPathname}/?${params.toString()}` as Route); - }; - const getImageGalleryListing = () => { - if (thisPathname?.includes("/listing-stay-detail")) { - return listingStayImageGallery; - } - if (thisPathname?.includes("/listing-car-detail")) { - return listingCarImageGallery; - } - if (thisPathname?.includes("/listing-experiences-detail")) { - return listingExperienceImageGallery; - } - return []; - }; return (
-
{children}
diff --git a/src/app/(listing-detail)/(components)/MobileFooterSticky.tsx b/src/components/MobileFooterSticky.tsx similarity index 50% rename from src/app/(listing-detail)/(components)/MobileFooterSticky.tsx rename to src/components/MobileFooterSticky.tsx index 410dc5a..302dc7a 100644 --- a/src/app/(listing-detail)/(components)/MobileFooterSticky.tsx +++ b/src/components/MobileFooterSticky.tsx @@ -4,71 +4,68 @@ import ButtonPrimary from "@/shared/ButtonPrimary"; import converSelectedDateToString from "@/utils/converSelectedDateToString"; import ModalReserveMobile from "./ModalReserveMobile"; import { useParams } from "next/navigation"; -import GuestsInput from "../listing-experiences-detail/GuestsInput"; import ClearDataButton from "@/app/(client-components)/(HeroSearchForm)/ClearDataButton"; import { UserPlusIcon } from "@heroicons/react/24/solid"; import { useToursContext } from "@/components/contexts/tourDetails"; import NcInputNumber from "@/components/NcInputNumber"; +import GuestsInput from "@/app/tours/[slug]/GuestsInput"; -const MobileFooterSticky = ({ data }) => { +const MobileFooterSticky = () => { const [startDate, setStartDate] = useState( new Date("2023/02/06") ); - const { setPassengers, passengers } = useToursContext(); + const { setPassengers, passengers , details } = useToursContext(); - const [guestAdultsInputValue, setGuestAdultsInputValue] = - useState(passengers); + const [guestAdultsInputValue, setGuestAdultsInputValue] = useState( + passengers.guestAdults || 0 + ); const handleChangeData = (value: number) => { - let newValue = { - guestAdults: guestAdultsInputValue, - }; setGuestAdultsInputValue(value); - newValue.guestAdults = value; - setPassengers(value); + setPassengers((prev) => ({ + ...prev, + guestAdults: value, + })); }; - console.log(data); - const r = /-?(\d+)$/; - const id: string = useParams().slug.match(r)[1]; + const { slug } = useParams(); + const id = slug?.match(/-?(\d+)$/)?.[1] || ""; + + // Calculate total based on guestAdults and data.price const totalGuests = guestAdultsInputValue; + const totalPrice = details?.price + ? (Number(details.price) * totalGuests).toLocaleString("en-US", { + style: "currency", + currency: "USD", + }) + : "N/A"; return ( -
+
- handleChangeData(value)} - max={10} - min={1} - label="Passsengers" - desc="Ages 13 or above" - /> + +
- - {data?.price * passengers} - + {totalPrice} ( - <> - - Reserve - - + 0 + ? "" + : "opacity-60 pointer-events-none" + }`} + href={`/add-listing/${id}`} + > + Reserve + )} />
diff --git a/src/app/(listing-detail)/(components)/ModalReserveMobile.tsx b/src/components/ModalReserveMobile.tsx similarity index 98% rename from src/app/(listing-detail)/(components)/ModalReserveMobile.tsx rename to src/components/ModalReserveMobile.tsx index 46b29d0..168ba48 100644 --- a/src/app/(listing-detail)/(components)/ModalReserveMobile.tsx +++ b/src/components/ModalReserveMobile.tsx @@ -76,4 +76,4 @@ const ModalReserveMobile: FC = ({ ); }; -export default ModalReserveMobile; +export default ModalReserveMobile; \ No newline at end of file diff --git a/src/components/contexts/tourDetails.tsx b/src/components/contexts/tourDetails.tsx index 8101217..368754d 100644 --- a/src/components/contexts/tourDetails.tsx +++ b/src/components/contexts/tourDetails.tsx @@ -3,6 +3,7 @@ import { usePathname } from "next/navigation"; import axiosInstance from "../api/axios"; import React, { createContext, useContext, useEffect, useState, ReactNode } from "react"; + interface ImageURL { sm: string; md: string; @@ -57,16 +58,21 @@ interface Tour { duration: string; } - export const Context = createContext(undefined); +interface Passengers { + guestAdults: number; + guestChildren: number; + guestInfants: number; +} + interface ToursContextType { details: TourDetails | undefined; - passengers: number; + passengers: Passengers; getTourData: (item: number) => Promise; - setPassengers: React.Dispatch>; + setPassengers: React.Dispatch>; setDetails: React.Dispatch>; - tours: {results : Tour[]}; + tours: { results: Tour[] }; countries: Country[]; } @@ -76,8 +82,12 @@ interface ContextProviderProps { export const ContextProvider = ({ children }: ContextProviderProps) => { const [details, setDetails] = useState(undefined); - const [passengers, setPassengers] = useState(0); - const [tours, setTours] = useState<{ results: Tour[] }>({ results: [] }); // <-- Wrap in results + const [passengers, setPassengers] = useState({ + guestAdults: 0, + guestChildren: 0, + guestInfants: 0, + }); + const [tours, setTours] = useState<{ results: Tour[] }>({ results: [] }); const [countries, setCountries] = useState([]); const path = usePathname(); @@ -92,18 +102,16 @@ export const ContextProvider = ({ children }: ContextProviderProps) => { }); }, []); - useEffect(() => { axiosInstance .get("/api/tours/") .then((response) => { - setTours({ results: response.data.results }); // <-- Expect results + setTours({ results: response.data.results }); }) .catch((error) => { console.error("Error fetching data:", error); }); }, []); - useEffect(() => { setDetails(undefined); @@ -117,8 +125,6 @@ export const ContextProvider = ({ children }: ContextProviderProps) => { console.error("Error fetching tour data:", error); } }; - - console.log(tours); return (