diff --git a/front/src/pods/embalse-search/components/index.tsx b/front/src/pods/embalse-search/components/index.tsx new file mode 100644 index 0000000..40cdd36 --- /dev/null +++ b/front/src/pods/embalse-search/components/index.tsx @@ -0,0 +1 @@ +export * from './recent-searches'; \ No newline at end of file diff --git a/front/src/pods/embalse-search/components/recent-searches/index.tsx b/front/src/pods/embalse-search/components/recent-searches/index.tsx new file mode 100644 index 0000000..853ce08 --- /dev/null +++ b/front/src/pods/embalse-search/components/recent-searches/index.tsx @@ -0,0 +1,3 @@ +export * from "./recent-searches.component" +export * from "./useRecentSearches.hook" +export * from "./recentSearches.bussiness" \ No newline at end of file diff --git a/front/src/pods/embalse-search/components/recent-searches/recent-searches.component.tsx b/front/src/pods/embalse-search/components/recent-searches/recent-searches.component.tsx new file mode 100644 index 0000000..b92229e --- /dev/null +++ b/front/src/pods/embalse-search/components/recent-searches/recent-searches.component.tsx @@ -0,0 +1,23 @@ +import Link from "next/link"; +import { EmbalseSearchModel } from "../../embalse-search.vm"; + +interface Props { + searches: EmbalseSearchModel[]; +} + +export const RecentSearches: React.FC = (props) => { + const { searches } = props; + + return ( + <> +

Búsquedas recientes

+ + + ); +}; diff --git a/front/src/pods/embalse-search/components/recent-searches/recentSearches.bussiness.ts b/front/src/pods/embalse-search/components/recent-searches/recentSearches.bussiness.ts new file mode 100644 index 0000000..298751b --- /dev/null +++ b/front/src/pods/embalse-search/components/recent-searches/recentSearches.bussiness.ts @@ -0,0 +1,41 @@ +import { EmbalseSearchModel } from "../../embalse-search.vm"; + + const MAX_SEARCHES = 5; + +export const getStoredSearches = (): EmbalseSearchModel[] => { + try { + const storedSearches = localStorage.getItem("recent-searches"); + if (storedSearches) { + const parsedStoredSearches = JSON.parse(storedSearches); + const isValidData = + Array.isArray(parsedStoredSearches) && + parsedStoredSearches.every( + (item) => + item && + typeof item.slug === "string" && + typeof item.name === "string", + ); + return isValidData ? parsedStoredSearches : []; + } else { + return []; + } + } catch (error) { + console.log( + "Error al recuperar búsquedas recientes en el localstorage ", + error, + ); + return []; + } +}; + +export const addNewSearchEntry = ( + newSearchEntry: EmbalseSearchModel, + recentSearches: EmbalseSearchModel[], +) => { + const filteredRecentSearches = recentSearches.filter( + (search) => search.slug !== newSearchEntry.slug, + ); + return [newSearchEntry, ...filteredRecentSearches].slice(0, MAX_SEARCHES); +}; + + diff --git a/front/src/pods/embalse-search/components/recent-searches/useRecentSearches.hook.ts b/front/src/pods/embalse-search/components/recent-searches/useRecentSearches.hook.ts new file mode 100644 index 0000000..bb0b857 --- /dev/null +++ b/front/src/pods/embalse-search/components/recent-searches/useRecentSearches.hook.ts @@ -0,0 +1,37 @@ +import { useState, useEffect } from "react"; +import { EmbalseSearchModel } from "../../embalse-search.vm"; +import { + addNewSearchEntry, + getStoredSearches, +} from "./recentSearches.bussiness"; + +export const useRecentSearches = () => { + const [recentSearches, setRecentSearches] = useState( + [], + ); + + useEffect(() => { + setRecentSearches(getStoredSearches()); + }, []); + + const addNewEmbalseToLatestSearchCollection = ( + newSearch: EmbalseSearchModel, + ) => { + setRecentSearches((prevSearches) => { + const updatedRecentSearchColletion = addNewSearchEntry( + newSearch, + prevSearches, + ); + localStorage.setItem( + "recent-searches", + JSON.stringify(updatedRecentSearchColletion), + ); + return updatedRecentSearchColletion; + }); + }; + + return { + recentSearches, + addNewEmbalseToLatestSearchCollection, + }; +}; diff --git a/front/src/pods/embalse-search/embalse-search.tsx b/front/src/pods/embalse-search/embalse-search.tsx index aeaffe8..a483f0a 100644 --- a/front/src/pods/embalse-search/embalse-search.tsx +++ b/front/src/pods/embalse-search/embalse-search.tsx @@ -9,6 +9,7 @@ import { EmbalseSearchModel } from "./embalse-search.vm"; import { getFilteredEmbalses as getFilteredEmbalsesBusiness } from "./embalse-search.business"; import { FilteredList } from "./components/filtered-list"; import { Input } from "./components/input"; +import { RecentSearches, useRecentSearches } from "./components"; interface Props { embalses: Embalse[]; @@ -22,6 +23,7 @@ export const EmbalseSearch: React.FC = (props) => { >([]); const [isNavigating, setIsNavigating] = useState(false); const [inputValue, setInputValue] = useState(""); + const { addNewEmbalseToLatestSearchCollection, recentSearches } = useRecentSearches(); const getFilteredEmbalses = (inputValue: string): EmbalseSearchModel[] => { return getFilteredEmbalsesBusiness(inputValue, embalses); @@ -42,12 +44,14 @@ export const EmbalseSearch: React.FC = (props) => { onSelectedItemChange: ({ selectedItem }) => { if (selectedItem) { setIsNavigating(true); + addNewEmbalseToLatestSearchCollection(selectedItem); router.push(`/embalse/${selectedItem.slug}`); } }, }); - const showNoResults = inputValue.length > 0 && filteredEmbalses.length === 0 && !isNavigating; + const showNoResults = + inputValue.length > 0 && filteredEmbalses.length === 0 && !isNavigating; return (
@@ -57,7 +61,7 @@ export const EmbalseSearch: React.FC = (props) => { >
@@ -65,7 +69,11 @@ export const EmbalseSearch: React.FC = (props) => { Embalses
- +
+

+ Encuentra toda la información disponible de los embalses de España +

+
@@ -78,13 +86,12 @@ export const EmbalseSearch: React.FC = (props) => { /> {showNoResults && }
-
-

- Encuentra toda la información disponible de los embalses de - España -

-
+ {recentSearches.length > 0 && ( +
+ +
+ )}
diff --git a/package-lock.json b/package-lock.json index e7cf2fb..599e730 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5643,7 +5643,7 @@ "vite": "bin/vite.js" }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -5652,14 +5652,14 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", - "less": "^4.0.0", + "less": "*", "lightningcss": "^1.21.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2"