-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[FE] feat: 리뷰, 꿀조합 좋아요에 낙관적 업데이트 적용 (#839)
* feat: 리뷰 좋아요에 낙관적 업데이트 적용 * feat: 리뷰 좋아요 버튼 컴포넌트 분리 * feat: 꿀조합 좋아요에 낙관적 업데이트 적용 * feat: client state로 좋아요를 관리하게끔 수정 * feat: 꿀조합 좋아요는 server state를 동기화하도록 수정 * style: console.log 제거 * feat: 토스트 에러 메시지 수정 * feat: 좋아요 개수도 업데이트 * fix: 객체 destructing이 안되어 수정
- Loading branch information
Showing
9 changed files
with
171 additions
and
118 deletions.
There are no files selected for viewing
60 changes: 0 additions & 60 deletions
60
frontend/src/components/Recipe/RecipeFavorite/RecipeFavorite.tsx
This file was deleted.
Oops, something went wrong.
43 changes: 43 additions & 0 deletions
43
frontend/src/components/Recipe/RecipeFavoriteButton/RecipeFavoriteButton.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import { theme, Button, Text } from '@fun-eat/design-system'; | ||
import styled from 'styled-components'; | ||
|
||
import { SvgIcon } from '@/components/Common'; | ||
import { useTimeout } from '@/hooks/common'; | ||
import { useRecipeFavoriteMutation } from '@/hooks/queries/recipe'; | ||
|
||
interface RecipeFavoriteProps { | ||
favorite: boolean; | ||
favoriteCount: number; | ||
recipeId: number; | ||
} | ||
|
||
const RecipeFavoriteButton = ({ recipeId, favorite, favoriteCount }: RecipeFavoriteProps) => { | ||
const { mutate } = useRecipeFavoriteMutation(Number(recipeId)); | ||
|
||
const handleToggleFavorite = async () => { | ||
mutate({ favorite: !favorite }); | ||
}; | ||
|
||
const [debouncedToggleFavorite] = useTimeout(handleToggleFavorite, 200); | ||
|
||
return ( | ||
<FavoriteButton type="button" variant="transparent" onClick={debouncedToggleFavorite}> | ||
<SvgIcon | ||
variant={favorite ? 'favoriteFilled' : 'favorite'} | ||
color={favorite ? 'red' : theme.colors.gray4} | ||
width={18} | ||
/> | ||
<Text weight="bold" size="lg"> | ||
{favoriteCount} | ||
</Text> | ||
</FavoriteButton> | ||
); | ||
}; | ||
|
||
export default RecipeFavoriteButton; | ||
|
||
const FavoriteButton = styled(Button)` | ||
display: flex; | ||
gap: 8px; | ||
align-items: center; | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
69 changes: 69 additions & 0 deletions
69
frontend/src/components/Review/ReviewFavoriteButton/ReviewFavoriteButton.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import { Text, Button, useTheme } from '@fun-eat/design-system'; | ||
import { useState } from 'react'; | ||
import styled from 'styled-components'; | ||
|
||
import { SvgIcon } from '@/components/Common'; | ||
import { useTimeout } from '@/hooks/common'; | ||
import { useReviewFavoriteMutation } from '@/hooks/queries/review'; | ||
|
||
interface ReviewFavoriteButtonProps { | ||
productId: number; | ||
reviewId: number; | ||
favorite: boolean; | ||
favoriteCount: number; | ||
} | ||
|
||
const ReviewFavoriteButton = ({ productId, reviewId, favorite, favoriteCount }: ReviewFavoriteButtonProps) => { | ||
const theme = useTheme(); | ||
|
||
const initialFavoriteState = { | ||
isFavorite: favorite, | ||
currentFavoriteCount: favoriteCount, | ||
}; | ||
|
||
const [favoriteInfo, setFavoriteInfo] = useState(initialFavoriteState); | ||
const { isFavorite, currentFavoriteCount } = favoriteInfo; | ||
|
||
const { mutate } = useReviewFavoriteMutation(productId, reviewId); | ||
|
||
const handleToggleFavorite = async () => { | ||
setFavoriteInfo((prev) => ({ | ||
isFavorite: !prev.isFavorite, | ||
currentFavoriteCount: isFavorite ? prev.currentFavoriteCount - 1 : prev.currentFavoriteCount + 1, | ||
})); | ||
|
||
mutate( | ||
{ favorite: !isFavorite }, | ||
{ | ||
onError: () => { | ||
setFavoriteInfo(initialFavoriteState); | ||
}, | ||
} | ||
); | ||
}; | ||
|
||
const [debouncedToggleFavorite] = useTimeout(handleToggleFavorite, 200); | ||
|
||
return ( | ||
<FavoriteButton | ||
type="button" | ||
variant="transparent" | ||
onClick={debouncedToggleFavorite} | ||
aria-label={`좋아요 ${currentFavoriteCount}개`} | ||
> | ||
<SvgIcon variant={isFavorite ? 'favoriteFilled' : 'favorite'} color={isFavorite ? 'red' : theme.colors.gray4} /> | ||
<Text as="span" weight="bold"> | ||
{currentFavoriteCount} | ||
</Text> | ||
</FavoriteButton> | ||
); | ||
}; | ||
|
||
export default ReviewFavoriteButton; | ||
|
||
const FavoriteButton = styled(Button)` | ||
display: flex; | ||
align-items: center; | ||
padding: 0; | ||
column-gap: 8px; | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters