"use client"; import dayjs from "dayjs"; import { isNull } from "lodash-es"; import { useSearchParams } from "next/navigation"; import { useCallback, useEffect, useState } from "react"; import { Button } from "@/components/ui/button/button"; import Card from "@/components/ui/card/card"; import LIcon from "@/components/ui/lucid-icon/lucid-icon"; import type { AppliedFilterData } from "@/components/widget/applied-filter/applied-filter"; import { useAppliedFilter } from "@/components/widget/applied-filter/applied-filter"; import type { EventPayload, OnSubmitPayload, } from "@/components/widget/core-list/core-list"; import CoreList from "@/components/widget/core-list/core-list"; import { FilterItemTypeEnum } from "@/components/widget/core-list/core-list-filter/core-list-filter"; import { DUMMY_TRANSFER_SEARCH_REQUEST } from "@/data/dummy/transfer/search-list"; import { useApp } from "@/hooks/useApp"; import { useLocale } from "@/hooks/useLocale"; import { storageManager } from "@/libs/storage-manager"; import { ILoaderKeys } from "@/models/loader.model"; import { useTransferDetailMutation } from "@/services/eva-display/transfer/transfer-detail.service"; import { useTransferListService } from "@/services/eva-display/transfer/transfer-search/transfer-search.services"; import type { ITransferSearchResponseItem } from "@/services/eva-display/transfer/transfer-search/transfer-search.types"; import type { ITransferList } from "@/services/eva-display/transfer/transfer-search/transfer-search-service.serializer"; import { useLoaderStore } from "@/store/loader-store/use-loader-store"; import { useTransferSummary } from "../../summary/hooks/use-transfer-summary"; import { useTransferTravelPlanner } from "../../travel-planner/hooks/use-transfer-travel-planner"; import { transferListItemFromApi } from "../libs/transfer-list-serializers"; import TransferListItem from "./transfer-list-item"; const TransferList = () => { const { t } = useLocale(); const [state, setState] = useState({ data: [] as ITransferSearchResponseItem[], loading: true, filterMeta: null as any | null, searchMetaData: { searchId: null, requestKey: null, }, lastResponse: null as ITransferList | null, groupId: 0, selectedItem: null as ITransferSearchResponseItem | null, initialPriceValue: { min: null as number | null, max: null as number | null, }, }); const { removeLoader } = useLoaderStore(); const [gettingItemKey, setGettingItemKey] = useState(null); const { setSearchAndDetailData, goSummary, data } = useTransferSummary(); const { data: tpData, isReady: tpIsReady } = useTransferTravelPlanner(); const { getTransferListService } = useTransferListService(); const transferDetailMutation = useTransferDetailMutation(); const searchParams = useSearchParams(); const destination = searchParams.get("destination"); const departure = searchParams.get("departure"); const { isB2E } = useApp(); const [requestDatas, setRequestData] = useState({ ...DUMMY_TRANSFER_SEARCH_REQUEST, Filter: { ...DUMMY_TRANSFER_SEARCH_REQUEST.Filter, IsPriceSortedByDesc: isB2E ? false : null, }, }); const { data: appliedFilters, replaceFilter, removeFilter, clearFilter, } = useAppliedFilter(); const setAppliedFilter = ( searchFilter: typeof DUMMY_TRANSFER_SEARCH_REQUEST.Filter, ) => { const isEconomicValue = ( isNull(searchFilter?.IsEconomic) ? null : searchFilter?.IsEconomic ) as null | boolean; if (isEconomicValue === null) { removeFilter({ filterKey: "transfer-type", filterValue: "transfer-type", filterLabel: "", }); } else { replaceFilter({ filterKey: "transfer-type", filterValue: isEconomicValue ? "economic" : "private", filterLabel: isEconomicValue ? t("Economic Transfer") : t("Private Transfer"), }); } }; const getData = useCallback( async (params: any) => { const requestData = { ...params }; setState((prevState) => ({ ...prevState, loading: true, })); const requestDataPassengers: any[] = []; const searchLegs: any[] = []; const adultCount = (tpData.payload?.passengers?.employee?.count ?? 0) + (tpData.payload?.passengers?.guest?.count ?? 0); const childCount = tpData.payload?.passengers?.child?.count ?? 0; Array(adultCount) .fill(adultCount) .forEach((_) => { requestDataPassengers.push({ PassengerType: "Adult", Age: 20, }); }); Array(childCount) .fill(childCount) .forEach((_) => { requestDataPassengers.push({ PassengerType: "Child", Age: 10, }); }); requestData.Passengers = requestDataPassengers; searchLegs.push({ OriginType: tpData.payload.departure?.type, DestinationType: tpData.payload.destination?.type, OriginId: tpData.payload.departure.id, DestinationId: tpData.payload.destination.id, DepartureTime: `${dayjs(tpData.payload.departureDate.date).format( "YYYY-MM-DD", )}T${tpData.payload.departureDate.time}:00.000Z`, }); if ( tpData.payload.returnDate && dayjs(tpData.payload.returnDate?.date).isValid() ) { searchLegs.push({ OriginType: tpData.payload.destination?.type, DestinationType: tpData.payload.departure?.type, OriginId: tpData.payload.destination.id, DestinationId: tpData.payload.departure.id, DepartureTime: `${dayjs(tpData.payload.returnDate.date).format( "YYYY-MM-DD", )}T${tpData.payload.returnDate.time}:00.000Z`, }); } requestData.Filter = { ...requestData.Filter, GroupId: state.groupId, }; if (state.groupId === 1) { requestData.SearchId = state.searchMetaData.searchId; } requestData.SearchLegs = searchLegs; const response = await getTransferListService(requestData as any); storageManager.delete("core-summary"); storageManager.delete("core-payment"); if (response) { setState((prevState) => ({ ...prevState, data: response.items ?? [], filterMeta: response.filter, totalCount: response.totalCount, loading: false, lastResponse: response, searchMetaData: { searchId: response.searchId ?? null, requestKey: null, }, initialPriceValue: !prevState.initialPriceValue.min ? { min: response.filter?.priceMin ?? null, max: response.filter?.priceMax ?? null, } : prevState.initialPriceValue, })); } }, [ getTransferListService, state.groupId, state.searchMetaData.searchId, tpData.payload.departure.id, tpData.payload.departure?.type, tpData.payload.departureDate.date, tpData.payload.departureDate.time, tpData.payload.destination.id, tpData.payload.destination?.type, tpData.payload?.passengers?.child?.count, tpData.payload?.passengers?.employee?.count, tpData.payload?.passengers?.guest?.count, tpData.payload.returnDate, ], ); const handleGetData = (requestData: typeof DUMMY_TRANSFER_SEARCH_REQUEST) => { getData({ ...requestData, }); setAppliedFilter( requestData.Filter as typeof DUMMY_TRANSFER_SEARCH_REQUEST.Filter, ); }; const handleChangeListActions = (eventPayload: EventPayload) => { if (eventPayload.type === "sort") { if ( eventPayload.payload.name === "price" && eventPayload.payload.value === "PriceAscending" ) { setRequestData((prevState: any) => ({ ...prevState, SearchId: state.searchMetaData.searchId, Filter: { ...prevState.Filter, IsPriceSortedByDesc: false, }, })); } else if ( eventPayload.payload.name === "price" && eventPayload.payload.value === "PriceDescending" ) { setRequestData((prevState: any) => ({ ...prevState, SearchId: state.searchMetaData.searchId, Filter: { ...prevState.Filter, IsPriceSortedByDesc: true, }, })); } else { setRequestData((prevState: any) => { return { ...prevState, SearchId: state.searchMetaData.searchId, Filter: { ...prevState.Filter, IsPriceSortedByDesc: null, }, }; }); } } }; const handleSubmitListFilter = ( filterValues: | OnSubmitPayload["payload"] | { "total-price": { start: number; end: number }; "transfer-type": string[]; }, ) => { if (!state.initialPriceValue.min || !state.initialPriceValue.max) { return; } setRequestData((prevState: any) => { let isEconomic = null; const hasEconomic = filterValues["transfer-type"].includes("economic"); const hasPrivate = filterValues["transfer-type"].includes("private"); if (hasEconomic) isEconomic = true; if (!hasEconomic && hasPrivate) isEconomic = false; const priceMinValue = filterValues["total-price"].start === state?.initialPriceValue?.min ? 1 : filterValues["total-price"].start; const priceMaxValue = filterValues["total-price"].end === state?.initialPriceValue?.max ? 0 : filterValues["total-price"].end; const newState = { ...prevState, Filter: { ...prevState.Filter, PriceMin: isNull(priceMinValue) ? requestDatas?.Filter?.PriceMin : priceMinValue, PriceMax: isNull(priceMaxValue) ? requestDatas?.Filter?.PriceMax : priceMaxValue, IsEconomic: isEconomic, }, }; // Fetch data with new filter values handleGetData(newState); return newState; }); }; const handleClearFilter = () => { clearFilter(); setRequestData((prevState: any) => ({ ...prevState, Filter: { PriceMin: prevState.Filter.PriceMin ?? 1, PriceMax: prevState.Filter.PriceMax ?? 0, IsEconomic: null, Page: 1, GroupId: 0, PageSize: null, IsPriceSortedByDesc: null, }, })); }; const handleRemoveFilter = (item: AppliedFilterData) => { if (item.filterValue === "total-price") { setRequestData((prevState: any) => ({ ...prevState, Filter: { ...prevState.Filter, PriceMin: 1, PriceMax: 0, }, })); removeFilter({ filterKey: "total-price", filterValue: "total-price", filterLabel: "", }); } else if (item.filterKey === "transfer-type") { setRequestData((prevState: any) => { const newFilter = { ...prevState, Filter: { ...prevState.Filter, IsEconomic: null, }, }; handleGetData(newFilter); return newFilter; }); removeFilter({ filterKey: "transfer-type", filterValue: item.filterValue, filterLabel: "", }); } }; function prepareSelectedItems() { const filterData = requestDatas as any; const selectedItems: string[] = []; if (filterData.Filter?.IsEconomic === true) { selectedItems.push("economic"); } else if (filterData.Filter?.IsEconomic === false) { selectedItems.push("private"); } return selectedItems; } const sortValue = () => { switch (state?.filterMeta?.isPriceSortedByDesc) { case true: return "PriceDescending"; case false: return "PriceAscending"; default: return "Average"; } }; useEffect(() => { if (tpIsReady) { getData({ ...requestDatas, }); } setTimeout(() => { removeLoader(ILoaderKeys.HotelDetailLoaderKey); }, 250); // eslint-disable-next-line react-hooks/exhaustive-deps }, [tpIsReady, state.groupId]); const isMultiple = tpData?.payload?.returnDate && dayjs(tpData.payload?.returnDate?.date).isValid(); function filterItem(x: ITransferSearchResponseItem): boolean { if (!isMultiple) return true; if (!state.selectedItem) { return x.groupId === 0; } const conditions = [ x.groupId === 1, x.isEconomic === state.selectedItem.isEconomic, x.quota === state.selectedItem.quota, x.name === state.selectedItem.name, ]; return !conditions.includes(false); } const stateDataLength = state.data.filter(filterItem).length; return (
0 ? [ { name: "total-price", type: FilterItemTypeEnum.PRICE_RANGE, properties: { start: state.initialPriceValue.min ?? 0, end: state.initialPriceValue.max ?? 0, currencySymbol: "₺", label: t("Total Price"), }, }, { name: "transfer-type", type: FilterItemTypeEnum.SINGLE_CHECKBOX_LIST, properties: { label: t("Transfer Type"), isCollapsible: false, // This items are static, but its count are dynamic and they are coming from api items: [ ...(state?.filterMeta?.economicTransferCount === 0 ? [] : [ { key: "economic", value: "economic", label: `${t("Economic Transfer")} (${ state?.filterMeta?.economicTransferCount || 0 })`, }, ]), ...(state?.filterMeta?.privateTransferCount === 0 ? [] : [ { key: "private", value: "private", label: `${t("Private Transfer")} (${ state?.filterMeta?.privateTransferCount || 0 })`, }, ]), ], }, }, ] : [] } filterOptionValues={{ "total-price": { start: requestDatas?.Filter?.PriceMin !== 1 ? requestDatas?.Filter?.PriceMin : state.initialPriceValue.min && state.filterMeta?.priceMin, end: requestDatas?.Filter?.PriceMax !== 0 ? requestDatas?.Filter?.PriceMax : state.initialPriceValue.max && state.filterMeta?.priceMax, }, "transfer-type": prepareSelectedItems(), }} renderItem={(item) => ( { setGettingItemKey(item.key); const resp = await transferDetailMutation.mutateAsync({ TransferDetailRequest: { ProductKey: item.key, searchId: state.lastResponse?.searchId, }, }); const detailKey = resp?.result?.transferSegmentGroupItem[0]?.key; if (!detailKey) { return; } const summaryData = { searchId: state.lastResponse?.searchId, transferSegmentGroupItemKey: detailKey, searchItemKey: item.key, }; if (isMultiple) { if (!state.selectedItem) { setSearchAndDetailData({ detailKey: [detailKey ?? ""], passengersKeys: state.lastResponse?.passengerList ?? [], searchId: summaryData.searchId, searchItemKey: summaryData.searchItemKey, productExtraInfo: { images: [item.pictureUrl], }, }); setGettingItemKey(null); setState((prev) => ({ ...prev, selectedItem: item, groupId: 1, })); } else { setSearchAndDetailData({ detailKey: [ ...(data.payload.detailKey ?? []), summaryData.transferSegmentGroupItemKey ?? "", ], passengersKeys: state.lastResponse?.passengerList ?? [], searchId: summaryData.searchId, searchItemKey: summaryData.searchItemKey, productExtraInfo: { ...data.payload.productExtraInfo, images: [ ...(data.payload.productExtraInfo?.images ?? []), item.pictureUrl, ], }, }); setGettingItemKey(null); goSummary(); } return; } setSearchAndDetailData({ detailKey: [summaryData.transferSegmentGroupItemKey ?? ""], passengersKeys: state.lastResponse?.passengerList ?? [], searchId: summaryData.searchId, searchItemKey: summaryData.searchItemKey, productExtraInfo: { images: [item.pictureUrl], }, }); setGettingItemKey(null); goSummary(); }} /> )} hasMore={false} isLoading={state.loading} isEmpty={!state.loading && stateDataLength === 0} appliedFilters={appliedFilters} onRemoveFilter={handleRemoveFilter} onSubmit={handleSubmitListFilter} onChange={handleChangeListActions} onClearFilter={handleClearFilter} sortValue={sortValue()} totalCount={ state.groupId === 1 ? stateDataLength : state.lastResponse?.totalCount } renderHeader={() => { return (
{isMultiple && state.selectedItem && (
{t("Departure transfer selected.")}
)}

{`${departure} - ${destination}`}

{isMultiple && (
{state.groupId === 0 ? "Gidiş" : "Dönüş"}
)}
{t("{{count}} results found.", { count: stateDataLength, })}
); }} />
); }; export default TransferList;