diff --git a/package-lock.json b/package-lock.json index 38460d8..9cf304f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,7 +26,6 @@ "google-map-react": "^2.2.1", "lodash": "^4.17.21", "next": "^13.4.3", - "next-auth": "^4.24.7", "rc-slider": "^10.1.1", "react": "^18.2.0", "react-datepicker": "^4.11.0", @@ -476,14 +475,6 @@ "node": ">= 8" } }, - "node_modules/@panva/hkdf": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.1.1.tgz", - "integrity": "sha512-dhPeilub1NuIG0X5Kvhh9lH4iW3ZsHlnzwgwbOlgwQ2wG1IqFzsgHqmKPk3WzsdWAeaxKJxgM0+W433RmN45GA==", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, "node_modules/@pkgr/utils": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.1.tgz", @@ -1339,14 +1330,6 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "license": "MIT" }, - "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/copy-to-clipboard": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", @@ -3179,14 +3162,6 @@ "jiti": "bin/jiti.js" } }, - "node_modules/jose": { - "version": "4.15.9", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz", - "integrity": "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, "node_modules/js-cookie": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz", @@ -3564,33 +3539,6 @@ } } }, - "node_modules/next-auth": { - "version": "4.24.7", - "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-4.24.7.tgz", - "integrity": "sha512-iChjE8ov/1K/z98gdKbn2Jw+2vLgJtVV39X+rCP5SGnVQuco7QOr19FRNGMIrD8d3LYhHWV9j9sKLzq1aDWWQQ==", - "dependencies": { - "@babel/runtime": "^7.20.13", - "@panva/hkdf": "^1.0.2", - "cookie": "^0.5.0", - "jose": "^4.15.5", - "oauth": "^0.9.15", - "openid-client": "^5.4.0", - "preact": "^10.6.3", - "preact-render-to-string": "^5.1.19", - "uuid": "^8.3.2" - }, - "peerDependencies": { - "next": "^12.2.5 || ^13 || ^14", - "nodemailer": "^6.6.5", - "react": "^17.0.2 || ^18", - "react-dom": "^17.0.2 || ^18" - }, - "peerDependenciesMeta": { - "nodemailer": { - "optional": true - } - } - }, "node_modules/next/node_modules/postcss": { "version": "8.4.14", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", @@ -3668,11 +3616,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/oauth": { - "version": "0.9.15", - "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz", - "integrity": "sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==" - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -3804,14 +3747,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/oidc-token-hash": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.0.3.tgz", - "integrity": "sha512-IF4PcGgzAr6XXSff26Sk/+P4KZFJVuHAJZj3wgO3vX2bMdNVp/QXTP3P7CEm9V1IdG8lDLY3HhiqpsE/nOwpPw==", - "engines": { - "node": "^10.13.0 || >=12.0.0" - } - }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -3854,28 +3789,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/openid-client": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.5.0.tgz", - "integrity": "sha512-Y7Xl8BgsrkzWLHkVDYuroM67hi96xITyEDSkmWaGUiNX6CkcXC3XyQGdv5aWZ6dukVKBFVQCADi9gCavOmU14w==", - "dependencies": { - "jose": "^4.14.4", - "lru-cache": "^6.0.0", - "object-hash": "^2.2.0", - "oidc-token-hash": "^5.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, - "node_modules/openid-client/node_modules/object-hash": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", - "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", - "engines": { - "node": ">= 6" - } - }, "node_modules/optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -4144,26 +4057,6 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "license": "MIT" }, - "node_modules/preact": { - "version": "10.17.1", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.17.1.tgz", - "integrity": "sha512-X9BODrvQ4Ekwv9GURm9AKAGaomqXmip7NQTZgY7gcNmr7XE83adOMJvd3N42id1tMFU7ojiynRsYnY6/BRFxLA==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/preact" - } - }, - "node_modules/preact-render-to-string": { - "version": "5.2.6", - "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-5.2.6.tgz", - "integrity": "sha512-JyhErpYOvBV1hEPwIxc/fHWXPfnEGdRKxc8gFdAZ7XV4tlzyzG847XAyEZqoDnynP88akM4eaHcSOzNcLWFguw==", - "dependencies": { - "pretty-format": "^3.8.0" - }, - "peerDependencies": { - "preact": ">=10" - } - }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -4173,11 +4066,6 @@ "node": ">= 0.8.0" } }, - "node_modules/pretty-format": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz", - "integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==" - }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -5402,14 +5290,6 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/warning": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", diff --git a/package.json b/package.json index bc6415e..c76d8ab 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,6 @@ "google-map-react": "^2.2.1", "lodash": "^4.17.21", "next": "^13.4.3", - "next-auth": "^4.24.7", "rc-slider": "^10.1.1", "react": "^18.2.0", "react-datepicker": "^4.11.0", diff --git a/src/app/(client-components)/(Header)/MainNav1.tsx b/src/app/(client-components)/(Header)/MainNav1.tsx index dbfaad3..f43f1d6 100644 --- a/src/app/(client-components)/(Header)/MainNav1.tsx +++ b/src/app/(client-components)/(Header)/MainNav1.tsx @@ -1,3 +1,5 @@ +"use client" + import React, { FC, useContext, useEffect, useState } from "react"; import Logo from "@/shared/Logo"; import Navigation from "@/shared/Navigation/Navigation"; @@ -19,7 +21,12 @@ const MainNav1: FC = ({ className = "" }) => { const { status, setStatus } = useContext(user); const User = JSON.parse(localStorage.getItem("user")) + +useEffect(()=>{ User? setStatus(true) : setStatus(false) + +} , []) + return (
diff --git a/src/app/(stay-listings)/SectionGridFilterCard.tsx b/src/app/(stay-listings)/SectionGridFilterCard.tsx index 2afdb2e..8eed0cb 100644 --- a/src/app/(stay-listings)/SectionGridFilterCard.tsx +++ b/src/app/(stay-listings)/SectionGridFilterCard.tsx @@ -1,39 +1,72 @@ -import React, { FC } from "react"; +"use client"; + +import React, { FC, useContext, useEffect, useState } from "react"; import { DEMO_STAY_LISTINGS } from "@/data/listings"; import { StayDataType } from "@/data/types"; -import Pagination from "@/shared/Pagination"; import TabFilters from "./TabFilters"; import Heading2 from "@/shared/Heading2"; import StayCard2 from "@/components/StayCard2"; +import { Context } from "@/components/contexts/tourDetails"; +import { useParams, useSearchParams } from "next/navigation"; +import { useRouter } from "next/navigation"; export interface SectionGridFilterCardProps { className?: string; data?: StayDataType[]; } -const DEMO_DATA: StayDataType[] = DEMO_STAY_LISTINGS.filter((_, i) => i < 8); - const SectionGridFilterCard: FC = ({ className = "", - data = DEMO_DATA, + data = DEMO_STAY_LISTINGS, }) => { + const { countries, tours } = useContext(Context); + const [countryTours, setCountryTours] = useState(tours.results || []); + const [checked, setChecked] = useState<{ [key: string]: boolean }>({}); + + const searchParams = useSearchParams() +console.log(searchParams); + + // Get the list of selected countries + const filteredCountries = Object.keys(checked).filter((countryName) => checked[countryName]); + + console.log(searchParams.get("country")); + + + + useEffect(() => { + if (!tours.results) return; + + if (filteredCountries.length === 0) { + // If no country is selected, show all tours + setCountryTours(tours.results); + } else { + // Map selected country names to country codes + const selectedCountryCodes = countries + .filter((country) => filteredCountries.includes(country.name)) + .map((country) => country.code); + + // Filter tours based on selected country codes + const filteredTours = tours.results.filter((tour) => + selectedCountryCodes.includes(tour.destination_country) + ); + + setCountryTours(filteredTours); + } + }, [checked, countries, tours.results]); + return ( -
+
- +
- {data.map((stay) => ( - - ))} -
-
- + {countryTours.length > 0 ? ( + countryTours.map((stay) => ) + ) : ( +

No tours Available

+ )}
); diff --git a/src/app/(stay-listings)/SectionGridHasMap.tsx b/src/app/(stay-listings)/SectionGridHasMap.tsx index 22a96d0..403d72b 100644 --- a/src/app/(stay-listings)/SectionGridHasMap.tsx +++ b/src/app/(stay-listings)/SectionGridHasMap.tsx @@ -23,7 +23,7 @@ const SectionGridHasMap: FC = () => {
{/* CARDSSSS */}
- + {/* */}
@@ -74,24 +74,7 @@ const SectionGridHasMap: FC = () => { label="Search as I move the map" />
- - {DEMO_STAYS.map((item) => ( - - ))} - +
diff --git a/src/app/(stay-listings)/TabFilters.tsx b/src/app/(stay-listings)/TabFilters.tsx index 16f36d0..c5a69b2 100644 --- a/src/app/(stay-listings)/TabFilters.tsx +++ b/src/app/(stay-listings)/TabFilters.tsx @@ -1,6 +1,6 @@ "use client"; -import React, { Fragment, useState } from "react"; +import React, { Fragment, useEffect, useState } from "react"; import { Dialog, Popover, Transition } from "@headlessui/react"; import NcInputNumber from "@/components/NcInputNumber"; import ButtonPrimary from "@/shared/ButtonPrimary"; @@ -67,10 +67,18 @@ const moreFilter3 = [ const moreFilter4 = [{ name: " Pets allowed" }, { name: "Smoking allowed" }]; -const TabFilters = () => { +const TabFilters = ({data , +onChangeCountry = (item)=>{} + +}) => { const [isOpenMoreFilter, setisOpenMoreFilter] = useState(false); const [isOpenMoreFilterMobile, setisOpenMoreFilterMobile] = useState(false); const [rangePrices, setRangePrices] = useState([0, 1000]); + const [checkedItems, setCheckedItems] = useState({}); + +useEffect(()=>{ +onChangeCountry(checkedItems) +} , [checkedItems]) // const closeModalMoreFilter = () => setisOpenMoreFilter(false); @@ -78,6 +86,7 @@ const TabFilters = () => { // const closeModalMoreFilterMobile = () => setisOpenMoreFilterMobile(false); const openModalMoreFilterMobile = () => setisOpenMoreFilterMobile(true); +console.log(data); const renderXClear = () => { return ( @@ -113,37 +122,27 @@ const TabFilters = () => {
- {typeOfPaces.map((item) => ( -
+ {data.map((item) => ( +
{ + setCheckedItems((prev) => ({ + ...prev, + [item.name]: checked, + })); + }} />
))}
-
- - Clear - - - Apply - -
@@ -311,39 +310,53 @@ const TabFilters = () => { ); }; - const renderMoreFilterItem = ( - data: { - name: 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) => ( - - ))} -
+// Inside TabFilters component +const renderMoreFilterItem = ( + data: { + name: 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) => ( + { + setCheckedItems((prev) => ({ + ...prev, + [item.name]: checked, + })); + }} + /> + ))}
- ); - }; +
+ {list2.map((item) => ( + { + setCheckedItems((prev) => ({ + ...prev, + [item.name]: checked, + })); + }} + /> + ))} +
+
+ ); +}; + const renderTabMoreFilter = () => { return ( @@ -463,7 +476,7 @@ const TabFilters = () => { className={`flex lg:hidden items-center justify-center px-4 py-2 text-sm rounded-full border border-primary-500 bg-primary-50 text-primary-700 focus:outline-none cursor-pointer`} onClick={openModalMoreFilterMobile} > - More filters (3) + Countries {renderXClear()}
@@ -521,12 +534,12 @@ const TabFilters = () => {

Type of place

- {renderMoreFilterItem(typeOfPaces)} + {renderMoreFilterItem(data)}
{/* ---- */} -
+ {/*

Range Prices

@@ -592,49 +605,49 @@ const TabFilters = () => {
-
+
*/} {/* ---- */} -
+ {/*

Rooms and beds

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

Amenities

{renderMoreFilterItem(moreFilter1)}
-
+
*/} {/* ---- */} -
+ {/*

Facilities

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

Property type

{renderMoreFilterItem(moreFilter3)}
-
+
*/} {/* ---- */} -
+ {/*

House rules

{renderMoreFilterItem(moreFilter4)}
-
+
*/}
@@ -665,9 +678,9 @@ const TabFilters = () => {
{renderTabsTypeOfPlace()} - {renderTabsPriceRage()} - {renderTabsRoomAndBeds()} - {renderTabMoreFilter()} + {/* {renderTabsPriceRage()} */} + {/* {renderTabsRoomAndBeds()} */} + {/* {renderTabMoreFilter()} */}
{renderTabMoreFilterMobile()}
diff --git a/src/app/(stay-listings)/layout.tsx b/src/app/(stay-listings)/layout.tsx index 2cbfe12..35fe9a8 100644 --- a/src/app/(stay-listings)/layout.tsx +++ b/src/app/(stay-listings)/layout.tsx @@ -5,6 +5,7 @@ import SectionSliderNewCategories from "@/components/SectionSliderNewCategories" import SectionSubscribe2 from "@/components/SectionSubscribe2"; import React, { ReactNode } from "react"; import SectionHeroArchivePage from "../(server-components)/SectionHeroArchivePage"; +import SectionHero from "../(server-components)/SectionHero"; const Layout = ({ children }: { children: ReactNode }) => { return ( @@ -13,7 +14,7 @@ const Layout = ({ children }: { children: ReactNode }) => { {/* SECTION HERO */}
- +
{children} @@ -32,12 +33,9 @@ const Layout = ({ children }: { children: ReactNode }) => { {/* SECTION */} - {/* SECTION */}
- -
diff --git a/src/app/(stay-listings)/listing-stay-map/page.tsx b/src/app/(stay-listings)/listing-stay-map/page.tsx index 420331b..7280731 100644 --- a/src/app/(stay-listings)/listing-stay-map/page.tsx +++ b/src/app/(stay-listings)/listing-stay-map/page.tsx @@ -1,12 +1,13 @@ import React, { FC } from "react"; import SectionGridHasMap from "../SectionGridHasMap"; +import SectionGridFilterCard from "../SectionGridFilterCard"; export interface ListingStayMapPageProps {} const ListingStayMapPage: FC = ({}) => { return (
- +
); }; diff --git a/src/app/custom-history/page.tsx b/src/app/custom-history/page.tsx new file mode 100644 index 0000000..066d41b --- /dev/null +++ b/src/app/custom-history/page.tsx @@ -0,0 +1,111 @@ +'use client'; + +import React, { FC, useEffect, useState } from 'react'; +import axiosInstance from '@/components/api/axios'; +import { TrashIcon } from '@heroicons/react/24/outline'; // Import the Trash icon for the delete button +import { FaWhatsapp } from "react-icons/fa"; + + +export interface PageAddListing10Props {} + +const PageAddListing10: FC = () => { + const [tours, setTours] = useState([]); + const [toursDetail, setToursDetail] = useState([]); + const [user, setUser] = useState(null); + + useEffect(() => { + const userData = localStorage.getItem('user'); + if (userData) { + const parsedUser = JSON.parse(userData); + setUser(parsedUser); + + axiosInstance('/api/trip/custom/orders/', { + headers: { + Authorization: `token ${parsedUser.token}`, + }, + }) + .then((response) => { + setTours(response.data.results); + console.log(response); + + + // Parse tour details + const details = response.data.results.map((item) => + JSON.parse(item.detail) + ); + setToursDetail(details); + }) + .catch((error) => { + console.log(error); + }); + } + }, []); + + const deleteTour = (tour)=>{ + const selected = tours.find((item)=>{ + return JSON.parse(item.detail) === tour + }) + console.log(JSON.parse(tours[0].detail ) == tour.title[1].title ,JSON.parse(tours[0].detail ) , tour) + + } +console.log(tours); + + return ( +
+
+

Custom Trip History

+ 2023 Dec 02 | 16:17 +
+

Successfully Registered

+ {toursDetail.length > 0 ? ( + toursDetail.map((item, index) => ( +
+
+
+

Origin:

+

{item['1']?.city || 'N/A'}

+
+ + {Object.keys(item) + .filter((key) => !isNaN(Number(key)) && Number(key) > 1) + .map((key) => ( +
+

{item[key].title}:

+

{item[key]?.city || 'N/A'}

+
+ ))} +
+ +
+
+

Estimated Cost: ${item.summary?.cost_estimate || 'N/A'}

+ +
+ +
+
+ )) + ) : ( +

No tours available.

+ )} + +
+

Contact Support

+ +
+
+ ); +}; + +export default PageAddListing10; diff --git a/src/app/custom-trip/page.tsx b/src/app/custom-trip/page.tsx index 680fc46..f67b3c2 100644 --- a/src/app/custom-trip/page.tsx +++ b/src/app/custom-trip/page.tsx @@ -1,12 +1,12 @@ "use client"; -import React, { useEffect, useState } from "react"; -import { FC } from "react"; +import React, { FC, useEffect, useState } from "react"; +import axiosInstance from "@/components/api/axios"; import ButtonPrimary from "@/shared/ButtonPrimary"; import FormItem from "../add-listing/FormItem"; -import axiosInstance from "@/components/api/axios"; import Select from "@/shared/Select"; import Input from "@/shared/Input"; +import { useRouter } from "next/navigation"; interface City { name: string; @@ -21,48 +21,239 @@ interface Country { interface CommonLayoutProps {} const CommonLayout: FC = () => { + const user = JSON.parse(localStorage.getItem("user")); + + const router = useRouter() + const [countries, setCountries] = useState([]); const [startCity, setStartCity] = useState(""); - const [endCity, setEndCity] = useState(""); + const [startDate, setStartDate] = useState(""); + const [passengers, setPassengers] = useState(1); const [transport, setTransport] = useState([]); const [hotel, setHotel] = useState([]); - const [selectedHotel, setSelectedHotel] = useState(""); - const [selectedTransport, setSelectedTransport] = useState(""); - const [destinations, setDestinations] = useState<{ endCity: string, transport: string, hotel: string }[]>([]); + const [estimatedCost, setEstimatedCost] = useState(0); + const [destinations, setDestinations] = useState< + { + endCity: string; + transport: string; + hotel: string; + duration: number; + finishDate: string; + transportCost: number; + hotelCost: number; + }[] + >([]); + const [isFormValid, setIsFormValid] = useState(false); + var special = [ + "Zeroth", + "First", + "Second", + "Third", + "Fourth", + "Fifth", + "Sixth", + "Seventh", + "Eighth", + "Ninth", + "Tenth", + "Eleventh", + "Twelfth", + "Thirteenth", + "Fourteenth", + "Fifteenth", + "Sixteenth", + "Seventeenth", + "Eighteenth", + "Nineteenth", + ]; + var deca = [ + "Twent", + "Thirt", + "Fort", + "Fift", + "Sixt", + "Sevent", + "Eight", + "Ninet", + ]; + + function stringifyNumber(n) { + if (n < 20) return special[n]; + if (n % 10 === 0) return deca[Math.floor(n / 10) - 2] + "ieth"; + return deca[Math.floor(n / 10) - 2] + "y-" + special[n % 10]; + } useEffect(() => { - axiosInstance.get("/api/cityguide/countries/?service=custom_trip") + axiosInstance + .get("/api/cityguide/countries/?service=custom_trip") .then((response) => setCountries(response.data.results)) - .catch((error) => console.error(error)); + .catch((error) => console.error("Error fetching countries:", error)); }, []); useEffect(() => { - - console.log(destinations[destinations.length-1]?.endCity); - if (destinations[destinations.length-1]?.endCity) { - axiosInstance.get(`/api/trip/custom/transport/?from_city=${startCity}&to_city=${destinations[destinations.length-1]?.endCity}`) - .then((response) => { console.log(response) - setTransport(response.data)}) - .catch((error) => console.error(error)); - - axiosInstance.get(`/api/trip/hotels/${destinations[destinations.length-1]?.endCity}/`) - .then((response) =>{ console.log(response) - setHotel(response.data.results)}) - - .catch((error) => console.error(error)); + const lastDestination = destinations[destinations.length - 1]; + if (lastDestination?.endCity) { + axiosInstance + .get( + `/api/trip/custom/transport/?from_city=${startCity.split("/")[2].trim()}&to_city=${lastDestination.endCity.split("/")[2].trim()}` + ) + .then((response) => setTransport(response.data)) + .catch((error) => + console.error("Error fetching transport options:", error) + ); + + axiosInstance + .get(`/api/trip/hotels/${lastDestination.endCity.split("/")[2].trim()}/`) + .then((response) => setHotel(response.data.results)) + .catch((error) => console.error("Error fetching hotels:", error)); } - }, [destinations]); + }, [destinations, startCity]); + + useEffect(() => { + updateEstimatedCost(); + }, [destinations, passengers]); + + useEffect(() => { + validateForm(); + }, [startCity, startDate, passengers, destinations]); + + const updateEstimatedCost = () => { + const totalCost = destinations.reduce((acc, destination) => { + const transportCost = destination.transportCost * passengers; + const hotelCost = + destination.hotelCost * destination.duration * passengers; + return acc + transportCost + hotelCost; + }, 0); + setEstimatedCost(totalCost); + }; + + const validateForm = () => { + const isValid = + startCity && + startDate && + passengers > 0 && + destinations.every( + (destination) => + destination.endCity && + destination.transport && + destination.hotel && + destination.duration > 0 && + destination.finishDate + ); + setIsFormValid(isValid); + }; const addDestination = () => { - setDestinations([...destinations, { endCity: "", transport: "", hotel: "" }]); + setDestinations([ + ...destinations, + { + endCity: "", + transport: "", + hotel: "", + duration: 1, + finishDate: "", + transportCost: 0, + hotelCost: 0, + }, + ]); }; - const handleDestinationChange = (index: number, field: string, value: string) => { + const handleDestinationChange = ( + index: number, + field: string, + value: string | number + ) => { const updatedDestinations = [...destinations]; - updatedDestinations[index] = { ...updatedDestinations[index], [field]: value }; + updatedDestinations[index] = { + ...updatedDestinations[index], + [field]: value, + }; + + if (field === "transport") { + const selected = transport.find( + (item) => item.transportaion.name === value + ); + updatedDestinations[index].transportCost = selected?.price || 0; + } + + if (field === "hotel") { + const selected = hotel.find((item) => item.name === value); + updatedDestinations[index].hotelCost = selected?.price_per_day || 0; + } + + if (field === "duration") { + const baseDate = + index === 0 || !updatedDestinations[index - 1]?.finishDate + ? new Date(startDate) + : new Date(updatedDestinations[index - 1].finishDate); + + const newFinishDate = new Date(baseDate); + newFinishDate.setDate(baseDate.getDate() + Number(value)); + + updatedDestinations[index].finishDate = newFinishDate + .toISOString() + .split("T")[0]; + } + setDestinations(updatedDestinations); + validateForm(); + }; + console.log(destinations); + + const submitTour = async () => { + const formData = { + destinations: destinations.map((destination, index) => ({ + name: `${destination.endCity.split("/")[0].trim()}-${destination.endCity.split("/")[1].trim()} `, + })), + price_estimate: JSON.stringify(estimatedCost), + detail: JSON.stringify({ + "1": { + title: "Begin Trip", + city: `${startCity.split("/")[0].trim()}-${startCity.split("/")[1].trim()} `, + number_passenger: `${passengers}`, + start_date: startDate.replace(/-/g, "/"), + }, + ...destinations.reduce((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, "/"), // adjust as needed + }; + return acc; + }, {}), + summary: { + cost_estimate: estimatedCost.toString(), + journery_schedule: `${startDate.replace(/-/g, "/")} To ${destinations[ + destinations.length - 1 + ]?.finishDate.replace(/-/g, "/")} Day ${destinations.length}`, + }, + }), + }; + try { + const response = await axiosInstance.post( + "/api/trip/custom/", + formData, + { + headers: { + Authorization: `token ${user.token}`, + "Content-Type": "application/json", + "X-CSRFToken": + "HaqCxkS63ejsvwmlmk360sbFowGtwfNS06vGDYMIfWmHTWzJdod7x0zMEeC9gBSX", + Accept: "application/json", + }, + } + ); + console.log("Response:", response.data); + router.push("/custom-history") + + } catch (error) { + console.error("Error sending trip details:", error); + } }; -console.log(destinations); return (
@@ -75,20 +266,22 @@ console.log(destinations);

Guide

First, write the origin of your departure, then choose the first - destination of your trip, the number of nights of stay and the - means of travel, then choose your travel destinations if you - wish. + destination of your trip, the number of nights of stay, and the + means of travel, then choose your travel destinations if you wish.

Begin your trip

- setStartCity(e.target.value)} + > {countries.flatMap((country) => country.city.map((city) => ( - )) @@ -97,10 +290,21 @@ console.log(destinations);
- + setStartDate(e.target.value)} + /> - + + setPassengers(Math.max(1, Number(e.target.value))) + } + min="1" + />
@@ -108,16 +312,18 @@ console.log(destinations); {destinations.map((destination, index) => (
-

Destination {index + 1}

+

{stringifyNumber(index + 1)} Destination

handleDestinationChange(index, 'transport', e.target.value)} + onChange={(e) => + handleDestinationChange( + index, + "transport", + e.target.value + ) + } > - {transport?.map((item) => - - )} + ))}
- + + handleDestinationChange( + index, + "duration", + Math.max(1, Number(e.target.value)) + ) + } + min="1" + /> - +
@@ -163,8 +395,20 @@ console.log(destinations);
- Add Destination - Continue + + Add Destination + + + Continue +
diff --git a/src/app/layout.tsx b/src/app/layout.tsx index c0945aa..6d3a110 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -3,7 +3,6 @@ import { Poppins } from "next/font/google"; import SiteHeader from "./(client-components)/(Header)/SiteHeader"; import ClientCommons from "./ClientCommons"; -import { SessionProvider } from "next-auth/react"; import { ContextProvider } from "@/components/contexts/tourDetails"; import "./globals.css"; import "@/fonts/line-awesome-1.3.0/css/line-awesome.css"; @@ -29,7 +28,6 @@ export default function RootLayout({ return ( - @@ -39,7 +37,6 @@ export default function RootLayout({