Skip to content

Commit

Permalink
feat(favorites): implement favorites functionality with persistent to…
Browse files Browse the repository at this point in the history
… local storage
  • Loading branch information
IdoBouskila committed Nov 30, 2024
1 parent 76b20d7 commit a4e2d20
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 4 deletions.
14 changes: 14 additions & 0 deletions client/src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,20 @@ main {
display: flex;
}

.favorite-button {
border: none;
color: #fff;
display: grid;
background: none;
place-items: center;
padding: 0.5rem;
}

.favorite-button:hover {
background: rgba(0, 0, 0, 0.2);
border-radius: 50%;
}

.current-weather-container {
gap: 0.25rem;
display: flex;
Expand Down
8 changes: 6 additions & 2 deletions client/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import tabs from '@utils/tabs';
import { useState } from 'react';
import SideNavigation from '@components/side-navigation';
import SearchBar from '@components/search-bar/search-bar';
import { FavoritesProvider } from '@context/favorites-provider';

function App() {
const [currentTab, setCurrentTab] = useState(tabs[0]);
Expand All @@ -18,8 +19,11 @@ function App() {
/>

<main>
<SearchBar />
<currentTab.component />
<FavoritesProvider>
<SearchBar />

<currentTab.component />
</FavoritesProvider>
</main>
</div>
</>
Expand Down
7 changes: 5 additions & 2 deletions client/src/components/search-bar/result-list.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { trpc } from '@utils/trpc';
import FavoriteButton from '@components/shared/favorite-button';

const ResultList: React.FC<{
searchQuery: string;
Expand All @@ -18,8 +19,10 @@ const ResultList: React.FC<{
{
data?.length ?
data.map((location) => (
<li key={ location.id }>
{ location.name }
<li key={ location.id } onClick={ () => console.error('Click')}>
<span>{ location.name }</span>

<FavoriteButton name={ location.name } />
</li>
))
:
Expand Down
26 changes: 26 additions & 0 deletions client/src/components/shared/favorite-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { GoHeart, GoHeartFill } from 'react-icons/go';
import { useFavorites } from '@context/favorites-provider';

const FavoriteButton: React.FC<{ name: string }> = ({ name }) => {
const { favorites, addFavorite, removeFavorite } = useFavorites();

const isFavorite = favorites.includes(name);

const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
e.stopPropagation();

if (isFavorite) {
return removeFavorite(name);
}

addFavorite(name);
};

return (
<button className='favorite-button' onClick={ handleClick }>
{ isFavorite ? <GoHeartFill /> : <GoHeart /> }
</button>
);
};

export default FavoriteButton;
32 changes: 32 additions & 0 deletions client/src/context/favorites-provider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { useContext, createContext } from 'react';
import usePersistedFavorites from '@hooks/use-persisted-favorites';

type FavoritesContextType = {
favorites: string[];
addFavorite: (name: string) => void;
removeFavorite: (name: string) => void;
};

const favoritesContext = createContext<FavoritesContextType | undefined>(undefined);

export const useFavorites = () => {
const context = useContext(favoritesContext);

if(! context) {
throw new Error('useFavorites must be used within a FavoritesProvider');
}

return context;
}

export const FavoritesProvider: React.FC<{
children: React.ReactNode;
}> = ({ children }) => {
const { favorites, addFavorite, removeFavorite } = usePersistedFavorites();

return (
<favoritesContext.Provider value={{ favorites, addFavorite, removeFavorite }}>
{ children }
</favoritesContext.Provider>
);
};
31 changes: 31 additions & 0 deletions client/src/hooks/use-persisted-favorites.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { useState, useEffect } from 'react';

const usePersistentFavorites = () => {
const [favorites, setFavorites] = useState<string[]>([]);

useEffect(() => {
const favorites = localStorage.getItem('favorites');

if(favorites) {
setFavorites(JSON.parse(favorites));
}
}, []);

return {
favorites,
addFavorite: (name: string) => {
const updatedFavorites = [...favorites, name];

setFavorites(updatedFavorites);
localStorage.setItem('favorites', JSON.stringify(updatedFavorites));
},
removeFavorite: (name: string) => {
const updatedFavorites = favorites.filter((favorite) => favorite !== name);

setFavorites(updatedFavorites);
localStorage.setItem('favorites', JSON.stringify(updatedFavorites));
},
};
};

export default usePersistentFavorites;

0 comments on commit a4e2d20

Please sign in to comment.