feat(results-page): enhance search with caching, pagination, and UI tweaks
- Add dynamic rendering and Node.js runtime config to location API for better performance - Improve ProductCardSkeleton with dark mode styling for consistent theming - Simplify Hero search placeholder to focus on product name input - Integrate caching, pagination, and cache clearing in results page for optimized search experience and user control
This commit is contained in:
1 parent
166abeb64e
commit
e4ed666074
11 files changed
+1301
-86
No files matched your search
@@ -0,0 +1,218 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect, useCallback } from "react";
|
||||
import { Product } from "@/lib/openFoodFactsApi";
|
||||
import { cacheManager, CachedSearch, FilterRecord } from "@/lib/cacheManager";
|
||||
|
||||
export interface SearchCacheState {
|
||||
isLoading: boolean;
|
||||
isCached: boolean;
|
||||
searchId: string | null;
|
||||
progress: {
|
||||
currentPage: number;
|
||||
totalPages: number;
|
||||
loadedProducts: number;
|
||||
totalProducts: number;
|
||||
} | null;
|
||||
error: string | null;
|
||||
}
|
||||
|
||||
export interface UseSearchCacheReturn {
|
||||
state: SearchCacheState;
|
||||
getCachedSearch: (
|
||||
query: string,
|
||||
country: string,
|
||||
filters?: FilterRecord
|
||||
) => CachedSearch | null;
|
||||
saveSearch: (
|
||||
query: string,
|
||||
country: string,
|
||||
products: Product[],
|
||||
totalCount: number,
|
||||
filters?: FilterRecord
|
||||
) => string;
|
||||
clearCache: (
|
||||
query?: string,
|
||||
country?: string,
|
||||
filters?: FilterRecord
|
||||
) => void;
|
||||
clearAllCaches: () => void;
|
||||
getCacheStats: () => ReturnType<typeof cacheManager.getCacheStats>;
|
||||
updateProgress: (
|
||||
currentPage: number,
|
||||
totalPages: number,
|
||||
loadedProducts: number,
|
||||
totalProducts: number
|
||||
) => void;
|
||||
setError: (error: string | null) => void;
|
||||
setLoading: (loading: boolean) => void;
|
||||
}
|
||||
|
||||
export function useSearchCache(): UseSearchCacheReturn {
|
||||
const [state, setState] = useState<SearchCacheState>({
|
||||
isLoading: false,
|
||||
isCached: false,
|
||||
searchId: null,
|
||||
progress: null,
|
||||
error: null,
|
||||
});
|
||||
|
||||
const getCachedSearch = useCallback(
|
||||
(
|
||||
query: string,
|
||||
country: string,
|
||||
filters?: FilterRecord
|
||||
): CachedSearch | null => {
|
||||
try {
|
||||
const cached = cacheManager.getSearch(query, country, filters);
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
isCached: !!cached,
|
||||
searchId: cached?.searchId || null,
|
||||
error: null,
|
||||
}));
|
||||
return cached;
|
||||
} catch (error) {
|
||||
console.error("Erro ao buscar cache:", error);
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
error: "Erro ao acessar cache",
|
||||
}));
|
||||
return null;
|
||||
}
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const saveSearch = useCallback(
|
||||
(
|
||||
query: string,
|
||||
country: string,
|
||||
products: Product[],
|
||||
totalCount: number,
|
||||
filters?: FilterRecord
|
||||
): string => {
|
||||
try {
|
||||
const searchId = cacheManager.saveSearch(
|
||||
query,
|
||||
country,
|
||||
products,
|
||||
totalCount,
|
||||
filters
|
||||
);
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
searchId,
|
||||
isCached: true,
|
||||
error: null,
|
||||
}));
|
||||
return searchId;
|
||||
} catch (error) {
|
||||
console.error("Erro ao salvar cache:", error);
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
error: "Erro ao salvar cache",
|
||||
}));
|
||||
return "";
|
||||
}
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const clearCache = useCallback(
|
||||
(query?: string, country?: string, filters?: FilterRecord) => {
|
||||
try {
|
||||
if (query && country) {
|
||||
cacheManager.removeSearch(query, country, filters);
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
isCached: false,
|
||||
searchId: null,
|
||||
}));
|
||||
} else {
|
||||
cacheManager.clearAllCaches();
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
isCached: false,
|
||||
searchId: null,
|
||||
}));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Erro ao limpar cache:", error);
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
error: "Erro ao limpar cache",
|
||||
}));
|
||||
}
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const clearAllCaches = useCallback(() => {
|
||||
clearCache();
|
||||
}, [clearCache]);
|
||||
|
||||
const getCacheStats = useCallback(() => {
|
||||
return cacheManager.getCacheStats();
|
||||
}, []);
|
||||
|
||||
const updateProgress = useCallback(
|
||||
(
|
||||
currentPage: number,
|
||||
totalPages: number,
|
||||
loadedProducts: number,
|
||||
totalProducts: number
|
||||
) => {
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
progress: {
|
||||
currentPage,
|
||||
totalPages,
|
||||
loadedProducts,
|
||||
totalProducts,
|
||||
},
|
||||
}));
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const setError = useCallback((error: string | null) => {
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
error,
|
||||
}));
|
||||
}, []);
|
||||
|
||||
const setLoading = useCallback((loading: boolean) => {
|
||||
setState((prev) => ({
|
||||
...prev,
|
||||
isLoading: loading,
|
||||
error: loading ? null : prev.error,
|
||||
}));
|
||||
}, []);
|
||||
|
||||
// Limpar estado quando componente desmonta
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
setState({
|
||||
isLoading: false,
|
||||
isCached: false,
|
||||
searchId: null,
|
||||
progress: null,
|
||||
error: null,
|
||||
});
|
||||
};
|
||||
}, []);
|
||||
|
||||
return {
|
||||
state,
|
||||
getCachedSearch,
|
||||
saveSearch,
|
||||
clearCache,
|
||||
clearAllCaches,
|
||||
getCacheStats,
|
||||
updateProgress,
|
||||
setError,
|
||||
setLoading,
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user