Skip to content

Commit d909a0d

Browse files
authored
Merge pull request #193 from Lemoncode/feature/#183-save-user-recent-searches-(last-5)
Feature/#183 save user recent searches (last 5)
2 parents ab62367 + 184f926 commit d909a0d

7 files changed

Lines changed: 128 additions & 16 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './recent-searches';
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export * from "./recent-searches.component"
2+
export * from "./useRecentSearches.hook"
3+
export * from "./recentSearches.bussiness"
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import Link from "next/link";
2+
import { EmbalseSearchModel } from "../../embalse-search.vm";
3+
4+
interface Props {
5+
searches: EmbalseSearchModel[];
6+
}
7+
8+
export const RecentSearches: React.FC<Props> = (props) => {
9+
const { searches } = props;
10+
11+
return (
12+
<>
13+
<h3>Búsquedas recientes</h3>
14+
<ul>
15+
{searches.map((item) => (
16+
<li key={item.slug} className="mt-3">
17+
<Link className="link-accessible" href={`/embalse/${item.slug}`}>{item.name} </Link>
18+
</li>
19+
))}
20+
</ul>
21+
</>
22+
);
23+
};
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { EmbalseSearchModel } from "../../embalse-search.vm";
2+
3+
const MAX_SEARCHES = 5;
4+
5+
export const getStoredSearches = (): EmbalseSearchModel[] => {
6+
try {
7+
const storedSearches = localStorage.getItem("recent-searches");
8+
if (storedSearches) {
9+
const parsedStoredSearches = JSON.parse(storedSearches);
10+
const isValidData =
11+
Array.isArray(parsedStoredSearches) &&
12+
parsedStoredSearches.every(
13+
(item) =>
14+
item &&
15+
typeof item.slug === "string" &&
16+
typeof item.name === "string",
17+
);
18+
return isValidData ? parsedStoredSearches : [];
19+
} else {
20+
return [];
21+
}
22+
} catch (error) {
23+
console.log(
24+
"Error al recuperar búsquedas recientes en el localstorage ",
25+
error,
26+
);
27+
return [];
28+
}
29+
};
30+
31+
export const addNewSearchEntry = (
32+
newSearchEntry: EmbalseSearchModel,
33+
recentSearches: EmbalseSearchModel[],
34+
) => {
35+
const filteredRecentSearches = recentSearches.filter(
36+
(search) => search.slug !== newSearchEntry.slug,
37+
);
38+
return [newSearchEntry, ...filteredRecentSearches].slice(0, MAX_SEARCHES);
39+
};
40+
41+
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { useState, useEffect } from "react";
2+
import { EmbalseSearchModel } from "../../embalse-search.vm";
3+
import {
4+
addNewSearchEntry,
5+
getStoredSearches,
6+
} from "./recentSearches.bussiness";
7+
8+
export const useRecentSearches = () => {
9+
const [recentSearches, setRecentSearches] = useState<EmbalseSearchModel[]>(
10+
[],
11+
);
12+
13+
useEffect(() => {
14+
setRecentSearches(getStoredSearches());
15+
}, []);
16+
17+
const addNewEmbalseToLatestSearchCollection = (
18+
newSearch: EmbalseSearchModel,
19+
) => {
20+
setRecentSearches((prevSearches) => {
21+
const updatedRecentSearchColletion = addNewSearchEntry(
22+
newSearch,
23+
prevSearches,
24+
);
25+
localStorage.setItem(
26+
"recent-searches",
27+
JSON.stringify(updatedRecentSearchColletion),
28+
);
29+
return updatedRecentSearchColletion;
30+
});
31+
};
32+
33+
return {
34+
recentSearches,
35+
addNewEmbalseToLatestSearchCollection,
36+
};
37+
};

front/src/pods/embalse-search/embalse-search.tsx

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { EmbalseSearchModel } from "./embalse-search.vm";
99
import { getFilteredEmbalses as getFilteredEmbalsesBusiness } from "./embalse-search.business";
1010
import { FilteredList } from "./components/filtered-list";
1111
import { Input } from "./components/input";
12+
import { RecentSearches, useRecentSearches } from "./components";
1213

1314
interface Props {
1415
embalses: Embalse[];
@@ -22,6 +23,7 @@ export const EmbalseSearch: React.FC<Props> = (props) => {
2223
>([]);
2324
const [isNavigating, setIsNavigating] = useState<boolean>(false);
2425
const [inputValue, setInputValue] = useState<string>("");
26+
const { addNewEmbalseToLatestSearchCollection, recentSearches } = useRecentSearches();
2527

2628
const getFilteredEmbalses = (inputValue: string): EmbalseSearchModel[] => {
2729
return getFilteredEmbalsesBusiness(inputValue, embalses);
@@ -42,12 +44,14 @@ export const EmbalseSearch: React.FC<Props> = (props) => {
4244
onSelectedItemChange: ({ selectedItem }) => {
4345
if (selectedItem) {
4446
setIsNavigating(true);
47+
addNewEmbalseToLatestSearchCollection(selectedItem);
4548
router.push(`/embalse/${selectedItem.slug}`);
4649
}
4750
},
4851
});
4952

50-
const showNoResults = inputValue.length > 0 && filteredEmbalses.length === 0 && !isNavigating;
53+
const showNoResults =
54+
inputValue.length > 0 && filteredEmbalses.length === 0 && !isNavigating;
5155

5256
return (
5357
<div className="relative flex flex-1 flex-col overflow-hidden p-8">
@@ -57,15 +61,19 @@ export const EmbalseSearch: React.FC<Props> = (props) => {
5761
></div>
5862
<div className="flex grow flex-col items-center justify-center">
5963
<section
60-
className="bg-base-100 absolute flex max-w-10/12 flex-col gap-8 rounded-xl p-8 shadow-lg"
64+
className="bg-base-100 absolute flex max-w-10/12 flex-col gap-3 rounded-xl p-8 shadow-lg"
6165
aria-labelledby="search-title"
6266
>
6367
<div className="text-center">
6468
<h2 id="search-title" className="font-bold">
6569
Embalses
6670
</h2>
6771
</div>
68-
72+
<div>
73+
<p className="text-sm">
74+
Encuentra toda la información disponible de los embalses de España
75+
</p>
76+
</div>
6977
<div className="flex flex-col gap-4">
7078
<div className="relative" role="search">
7179
<Input getInputProps={getInputProps} />
@@ -78,13 +86,12 @@ export const EmbalseSearch: React.FC<Props> = (props) => {
7886
/>
7987
{showNoResults && <NoResult inputValue={inputValue} />}
8088
</div>
81-
<div>
82-
<p className="text-sm">
83-
Encuentra toda la información disponible de los embalses de
84-
España
85-
</p>
86-
</div>
8789
</div>
90+
{recentSearches.length > 0 && (
91+
<div className="mt-5">
92+
<RecentSearches searches={recentSearches} />
93+
</div>
94+
)}
8895
</section>
8996
</div>
9097
</div>

package-lock.json

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)