Vitron-Front/app/requestHandler/use-search-hooks.ts
2026-04-29 01:44:16 +03:30

122 lines
3.7 KiB
TypeScript

import { useInfiniteQuery, useQuery } from "@tanstack/react-query";
import { useSearchParams } from "@remix-run/react";
import {
ApiSearchV1ListRequest,
} from "../../src/api/types";
import {
ProductSearchResult,
SearchResponse,
SellerSearchResult,
} from "../../src/api/types/models";
import { createSearchSystemApi } from "~/utils/api-client-factory";
/**
* Hook to fetch autocomplete suggestions from the API
* Cancels previous requests when a new search is initiated
*/
export const useSearchAutocomplete = (query: string) => {
return useQuery({
queryKey: ["searchAutocomplete", query],
queryFn: async ({ signal }) => {
if (!query || query.trim() === "") {
return { suggestions: [] };
}
const searchApi = createSearchSystemApi();
// Create an init override function that includes the signal
const initOverrides = { signal };
try {
return await searchApi.apiSearchV1AutocompleteList(
{ q: query },
initOverrides
);
} catch (error) {
// If the request was aborted, return empty results
if (error instanceof DOMException && error.name === "AbortError") {
return { suggestions: [] };
}
throw error;
}
},
enabled: query.trim().length > 0,
staleTime: 1000 * 10, // 10 seconds
refetchOnWindowFocus: false,
});
};
/**
* Hook to fetch search results with infinite scrolling
* Reads search params from URL and fetches data accordingly
*/
export const useSearchInfinite = (routeQueryParam?: string) => {
const [searchParams] = useSearchParams();
// Get search query from route param and decode it
const query = routeQueryParam ? decodeURIComponent(routeQueryParam) : "";
// Get other search parameters from URL
const orderParam = searchParams.get("order");
const priceMinParam = searchParams.get("priceMin");
const priceMaxParam = searchParams.get("priceMax");
// Build search parameters
const searchQueryParams: ApiSearchV1ListRequest = {
q: query,
};
// Add sortBy parameter based on order
if (orderParam) {
// Map our order values to what the API expects in sortBy
switch (orderParam) {
case "cheap":
searchQueryParams.sortBy = "price";
break;
case "expensive":
searchQueryParams.sortBy = "-price"; // Negative for descending
break;
case "newest":
searchQueryParams.sortBy = "newest";
break;
default:
searchQueryParams.sortBy = orderParam;
}
}
// Add price filters if they exist
if (priceMinParam) searchQueryParams.priceMin = parseInt(priceMinParam, 10);
if (priceMaxParam) searchQueryParams.priceMax = parseInt(priceMaxParam, 10);
return useInfiniteQuery({
queryKey: ["search", searchQueryParams],
queryFn: async ({ pageParam = 1 }) => {
const searchApi = createSearchSystemApi();
return await searchApi.apiSearchV1List({
...searchQueryParams,
page: pageParam as number,
});
},
getNextPageParam: (lastPage: SearchResponse, allPages) => {
if (!lastPage || !lastPage.products || !lastPage.products.length) {
return undefined;
}
// Use the length of allPages to determine the next page number
const currentPage = allPages.length;
// If there are products and there should be more pages, return next page number
if (lastPage.products.length > 0) {
return currentPage + 1;
}
return undefined;
},
initialPageParam: 1,
enabled: !!query, // Only run query if search query exists
});
};
// Re-export types from the API for convenience
export type { ProductSearchResult, SellerSearchResult, SearchResponse };