/* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable no-console */ "use client"; import dayjs from "dayjs"; import { isArray, isEqual } from "lodash-es"; import { useCallback, useEffect, useState } from "react"; import type { AppliedFilterData } from "@/components/widget/applied-filter/applied-filter"; import { useAppliedFilter } from "@/components/widget/applied-filter/applied-filter"; import type { EventPayload } from "@/components/widget/core-list/core-list"; import CoreList from "@/components/widget/core-list/core-list"; import type { FilterItemType } from "@/components/widget/core-list/core-list-filter/core-list-filter"; import { FilterItemTypeEnum } from "@/components/widget/core-list/core-list-filter/core-list-filter"; import type { CoreListSortValueType } from "@/components/widget/core-list/core-list-sort"; import { DUMMY_TOUR_SEARCH_REQUEST } from "@/data/dummy/tour-list"; import { useBreakpoints } from "@/hooks/useBreakpoints"; import { useLocale } from "@/hooks/useLocale"; import { ILoaderKeys } from "@/models/loader.model"; import { SortTypeEnums } from "@/models/sort.model"; import type { ITourSearchRequest, ITourSearchResponseItem, SearchFilter, SearchFilterListItem, } from "@/services/eva-display/tour/tour-search/tour-search.types"; import { useTourSearchMutation } from "@/services/eva-display/tour/tour-search/tour-search-service"; import { useLoaderStore } from "@/store/loader-store/use-loader-store"; import { useTourTravelPlanner } from "../../travel-planner/hooks/use-tour-travel-planner"; import { useTourSearch } from "../hook/use-tour-search"; import { tourListItemFromApi } from "../libs/tour-list-serializers"; import TourListItem from "./tour-list-item"; const TourList = () => { const { t } = useLocale(); const { isDesktop } = useBreakpoints(); const { mutateAsync } = useTourSearchMutation(); const { isReady, data: searchData } = useTourTravelPlanner(); const { getVariables, setVariables } = useTourSearch(); const { removeLoader } = useLoaderStore(); const variables = getVariables(); const [sortingValue, setSortingValue] = useState("Average"); const { data: appliedFilters, setData: setAppliedFilters, updateFilterByKey, clearFilter, } = useAppliedFilter(); const [ { isLoading, searchMetaData: { totalTourCount, hasMore, searchId }, filterMeta, mergedData, initialPriceValue, }, setState, ] = useState({ data: [] as ITourSearchResponseItem[], isLoading: true, filterMeta: null as SearchFilter | null, searchMetaData: { searchId: null, requestKey: null, totalTourCount: 0, hasMore: true, }, initialPriceValue: { min: null as number | null, max: null as number | null, }, responseRecords: [] as { key: string; value: ITourSearchResponseItem[] }[], mergedData: [] as ITourSearchResponseItem[], }); const [requestData, setRequestData] = useState( DUMMY_TOUR_SEARCH_REQUEST, ); const filterMetaData: Partial< Record > = { roadRouteValues: filterMeta?.roadRouteValues || [], categoryValues: filterMeta?.categoryValues || [], regionValues: filterMeta?.regionValues || [], transportTypeValues: filterMeta?.transportTypeValues || [], minNightValues: filterMeta?.minNightValues || [], campaignFilterValues: filterMeta?.campaignFilterValues || [], }; function applySort(eventPayload: EventPayload) { let orderBy = SortTypeEnums.AVERAGE; if (eventPayload.payload.value === "PriceAscending") orderBy = SortTypeEnums.PRICE_ASCENDING; if (eventPayload.payload.value === "PriceDescending") orderBy = SortTypeEnums.PRICE_DESCENDING; setState((prevState) => ({ ...prevState, isLoading: true, mergedData: [], responseRecords: [], })); setRequestData((prevState: ITourSearchRequest) => ({ ...prevState, orderBy, searchId: null, })); } function applyLoadMore() { setRequestData((prevState: ITourSearchRequest) => ({ ...prevState, searchId: searchId || null, resetPage: false, })); } const handleChangedFilter = (eventPayload: EventPayload) => { if (eventPayload.type === "loadMore") applyLoadMore(); if (eventPayload.type === "sort") applySort(eventPayload); }; const setAppliedFilter = ( searchFilter: typeof DUMMY_TOUR_SEARCH_REQUEST.searchFilter, ) => { const exceptedKeys = ["Page", "maxPrice", "minPrice"]; const appliedFilterNewData = []; for (const [key, val] of Object.entries>( searchFilter as unknown as Record>, )) { if (typeof val !== undefined && !exceptedKeys.includes(key)) if (val?.length > 0 && val !== null) { const newFilterValues: AppliedFilterData[] = val?.map((item: any) => { return { filterKey: key, filterValue: item, filterLabel: (filterMetaData?.[key as keyof SearchFilter] || [])?.find( (filter: any) => filter.key === item, )?.value || "", }; }) || []; appliedFilterNewData.push(...newFilterValues); } } setAppliedFilters([...appliedFilterNewData]); }; const getData = useCallback( async (params: ITourSearchRequest) => { const payload = { ...params }; payload.startDate = dayjs(searchData.payload.dates?.checkIn).format( "YYYY-MM-DD", ); payload.endDate = dayjs(searchData.payload.dates?.checkOut).format( "YYYY-MM-DD", ); payload.keyword = Number.isNaN(searchData.payload.destination!.id) ? null : [ `${searchData.payload.destination?.id}|${searchData.payload.destination?.type}|"text"`, ]; payload.isDomestic = searchData.payload.isDomestic!; setState((prevState) => ({ ...prevState, initialPriceValue: { min: payload.searchFilter.minPrice ?? null, max: payload.searchFilter.maxPrice ?? null, }, })); mutateAsync(payload) .then((res) => { setState((prevState) => ({ ...prevState, data: res?.items, isLoading: false, filterMeta: res.filterResult, searchMetaData: { searchId: res.searchId, requestKey: null, totalTourCount: res.totalTourCount, hasMore: res.hasMore, }, responseRecords: [ ...prevState.responseRecords, { key: JSON.stringify(res?.items || {}), value: res?.items, }, ], mergedData: [ ...(requestData.resetPage ? [] : prevState.responseRecords .filter( (item) => item.key !== JSON.stringify(res?.items || {}), ) .map((item) => item.value) .flat(1)), ...(res?.items || []), ], })); }) .finally(() => {}); }, [ mutateAsync, isDesktop, requestData.resetPage, searchData?.payload.dates?.checkIn, searchData?.payload.dates?.checkOut, searchData?.payload.destination?.id, searchData?.payload.destination?.type, ], ); const handleRemoveFilter = (item: AppliedFilterData) => { if (item.filterKey === "total-price") { setRequestData((prevState: ITourSearchRequest) => ({ ...prevState, searchFilter: { ...prevState.searchFilter, minPrice: null, maxPrice: null, }, resetPage: true, searchId: null, })); return; } const appliedFiltersByKey = appliedFilters.filter( (filter) => filter.filterKey === item.filterKey && filter.filterValue !== item.filterValue, ); updateFilterByKey(item.filterKey, appliedFiltersByKey); const newFilterValues = appliedFiltersByKey.map( (appliedItem) => appliedItem.filterValue, ); const newFilter = { ...requestData.searchFilter, [item.filterKey]: newFilterValues?.length > 0 ? newFilterValues : null, Page: 1, }; setRequestData((prevState: any) => ({ ...prevState, searchFilter: { ...newFilter, }, resetPage: true, searchId: null, })); setState((prevState) => ({ ...prevState, isLoading: true, mergedData: [], responseRecords: [], })); }; const handleClearFilter = () => { clearFilter(); setRequestData((prevState: ITourSearchRequest) => ({ ...prevState, searchFilter: { roadRouteValues: null, categoryValues: null, regionValues: null, transportTypeValues: null, minNightValues: null, campaignFilterValues: null, minPrice: prevState.searchFilter.minPrice, maxPrice: prevState.searchFilter.maxPrice, }, resetPage: true, searchId: null, })); setState((prevState) => ({ ...prevState, isLoading: true, mergedData: [], responseRecords: [], })); }; function prepareFilterMeta( name: string, label: string, items: SearchFilterListItem[] | null | undefined, value: string[] | null | undefined, openCollapse = true, searchable = false, ) { return { name, type: FilterItemTypeEnum.CHECKBOX_LIST as FilterItemType, value, properties: { label, openCollapse, items: items ?.filter((item) => item.count > 0) ?.map((item) => ({ key: item.key, value: item.key, label: `${item.value} (${item.count})`, })) || [], placeholder: `${t("Region")} ${t("Search")}`, searchable, }, }; } useEffect(() => { if (isReady) { getData(requestData); setAppliedFilter( requestData.searchFilter as typeof DUMMY_TOUR_SEARCH_REQUEST.searchFilter, ); } let newSortingValue: CoreListSortValueType = "Average"; if (requestData?.orderBy === SortTypeEnums.PRICE_ASCENDING) { newSortingValue = "PriceAscending"; } else if (requestData?.orderBy === SortTypeEnums.PRICE_DESCENDING) { newSortingValue = "PriceDescending"; } setSortingValue(newSortingValue); setTimeout(() => { removeLoader(ILoaderKeys.ListingLoaderKey); }, 250); }, [getData, isReady, requestData, searchData]); if (!searchData) { return null; } return ( item.selected) .map((item) => item.key) || null, categoryValues: filterMeta?.categoryValues ?.filter((item) => item.selected) .map((item) => item.key) || null, regionValues: filterMeta?.regionValues ?.filter((item) => item.selected) .map((item) => item.key) || null, transportTypeValues: filterMeta?.transportTypeValues ?.filter((item) => item.selected) .map((item) => item.key) || null, minNightValues: filterMeta?.minNightValues ?.filter((item) => item.selected) .map((item) => item.key) || null, campaignFilterValues: filterMeta?.campaignFilterValues ?.filter((item) => item.selected) .map((item) => item.key) || null, }} noListDataText={t( "We couldn't find tours for the selected filters. Please try again with different filters", )} isEmpty={!mergedData?.length} isLoading={isLoading} totalCount={totalTourCount ?? 0} onSubmit={(filterValues) => { setState((prevState) => ({ ...prevState, isLoading: true, mergedData: [], responseRecords: [], })); if (!isEqual(requestData.searchFilter, filterValues)) { setRequestData((prevState: ITourSearchRequest) => ({ ...prevState, searchFilter: { ...prevState.searchFilter, ...Object.fromEntries( Object.entries(filterValues).map(([key, value]) => { let mappedValue = value; if (isArray(value)) if (value.length <= 0) mappedValue = null; return [key, mappedValue]; }), ), }, resetPage: true, searchId: null, })); } }} onChange={handleChangedFilter} data={mergedData ?? []} appliedFilters={appliedFilters} onRemoveFilter={handleRemoveFilter} onClearFilter={handleClearFilter} hasMore={hasMore ?? true} sortValue={sortingValue} renderItem={(item) => ( { if (variables) { setVariables({ ...variables, destination: { id: item.packageId, title: item.option.tourName, type: 2, typeName: "tur", }, target: "_blank", }); } }} /> )} renderHeader={() => { return (

{searchData.payload.destination?.value || ""}

{totalTourCount || 0} sonuç bulundu.
); }} /> ); }; export default TourList;