barneo-search-widget-lib
Version:
Библиотека для поиска по каталогу Barneo на Vue 3
213 lines (190 loc) • 6.61 kB
text/typescript
import { ref, computed } from "vue";
import type { SearchApiService } from "../../searchWidget/types";
import type { SharedStateConfig } from "../types";
import { useSharedState } from "./useSharedState";
export function useSearchStateManager(
apiService: SearchApiService | undefined,
config: SharedStateConfig = {}
) {
const sharedState = useSharedState();
const isPerformingDeepSearch = ref(false);
/**
* Унифицированная функция для выполнения поиска с фильтрами
*/
const performSearchWithFilters = async (
query: string,
options: {
filters?: Record<string, string[]>;
products?: Array<{ code: string; value_ids?: string[]; value_gte?: string; value_lte?: string }>;
activeFilters?: Array<{
id: string;
name: string;
code: string;
values: Array<{
id: string;
name: string;
isSelected: boolean;
}>;
}>;
pagination?: {
limit_products?: number;
limit_categories?: number;
limit_brands?: number;
offset_products?: number;
};
sort?: string;
updateSharedState?: boolean;
} = {}
) => {
const {
filters = {},
products = [],
activeFilters = [],
pagination = sharedState.searchState.pagination,
sort = sharedState.searchState.sort,
updateSharedState = true,
} = options;
if (!apiService || !query.trim()) return null;
// Если это глубокий поиск, устанавливаем флаг
if (updateSharedState) {
isPerformingDeepSearch.value = true;
sharedState.setLoading(true);
sharedState.setError("");
}
try {
const searchResponse = await apiService.searchCatalog({
is_fast_result: false,
include: [
"products",
"filters",
"correction",
"product_hints",
"full_hints",
"brands",
"categories",
"full_categories",
"full_brands",
],
sort: sort,
filter: {
location_id: apiService.getLocationId(),
query: query.trim(),
use_query_correction: true,
...filters,
...(products.length > 0 && { products }),
},
pagination,
load_full_products: {
location_id: apiService.getLocationId(),
include: ["properties"],
},
});
if (searchResponse && searchResponse.data) {
const results = searchResponse.data.full_products || [];
const filters = searchResponse.data.filters || [];
// Обновляем sharedState только если нужно
if (updateSharedState) {
sharedState.setSearchResults(
query.trim(),
results,
true,
searchResponse.data.full_products || results,
searchResponse.data.total_products || 0
);
// Сохраняем фильтры в общее состояние
if (filters.length > 0) {
sharedState.setFilters(filters);
}
// Сохраняем активные фильтры
if (activeFilters.length > 0) {
sharedState.setActiveFilters(activeFilters);
}
// Сохраняем сортировку, если она передана
if (sort) {
sharedState.setSort(sort);
}
// Сохраняем пагинацию, если она передана
if (pagination) {
sharedState.setPagination(pagination);
}
}
return searchResponse;
}
} catch (err) {
const errorMessage = err instanceof Error ? err.message : "Ошибка поиска";
if (updateSharedState) {
sharedState.setError(errorMessage);
}
throw err;
} finally {
if (updateSharedState) {
sharedState.setLoading(false);
isPerformingDeepSearch.value = false;
}
}
};
/**
* Выполняет глубокий поиск (для Enter или кнопки поиска)
*/
const performDeepSearch = async (query: string) => {
if (!apiService || !query.trim() || isPerformingDeepSearch.value) return;
// Сбрасываем сортировку и пагинацию при новом поиске
sharedState.setSort("relevance");
sharedState.resetPagination();
// Используем itemsPerPage из конфигурации, если он задан
const itemsPerPage = config.productsWidget?.itemsPerPage || 20;
return await performSearchWithFilters(query, {
updateSharedState: true,
pagination: {
limit_products: itemsPerPage,
limit_categories: 10,
limit_brands: 10,
offset_products: 0,
},
});
};
/**
* Выполняет быстрый поиск (для автодополнения)
*/
const performQuickSearch = async (query: string) => {
if (!apiService || !query.trim()) return;
try {
const searchResponse = await apiService.searchCatalog({
is_fast_result: true,
include: ["products", "product_hints", "full_hints"],
sort: "relevance",
filter: {
location_id: apiService.getLocationId(),
query: query.trim(),
use_query_correction: true,
},
pagination: {
limit_products: 5,
limit_categories: 3,
limit_brands: 3,
offset_products: 0,
},
});
if (searchResponse && searchResponse.data) {
const results = searchResponse.data.full_products || [];
// Для быстрого поиска не сохраняем в общее состояние
return {
results,
hints: searchResponse.data.product_hints || [],
fullHints: searchResponse.data.full_hints || [],
};
}
} catch (err) {
console.error("Ошибка быстрого поиска:", err);
throw err;
}
};
return {
// Экспортируем все из sharedState
...sharedState,
// Дополнительные методы для работы с API
performSearchWithFilters,
performDeepSearch,
performQuickSearch,
};
}