-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
템플릿 좋아요 기능 구현 #686
Merged
Merged
템플릿 좋아요 기능 구현 #686
Changes from 33 commits
Commits
Show all changes
34 commits
Select commit
Hold shift + click to select a range
f50d02e
feat(api): 좋아요 기능 API 함수 구현
vi-wolhwa 6f41fc6
feat(images): 좋아요 아이콘 생성 (like, unlike, unClickable)
vi-wolhwa dd169ea
test(mocks): templateList 데이터에 'isLiked', 'likeCount' 추가
vi-wolhwa 59a6e0c
feat(utils): 1000 이상의 숫자를 'k'단위로 표기하는 formatWithK 유틸함수 구현
vi-wolhwa 1085fa8
test(mocks): templateList 데이터에 'member' 정보 추가
vi-wolhwa 704c712
feat(images): 'like' 아이콘에 'size' 변수 추가 및 색상 변경
vi-wolhwa ea64410
feat(LikeWidget): 좋아요 위젯 구현
vi-wolhwa e134264
feat(TemplateCard): 템플릿 카드에 좋아요 위젯 적용
vi-wolhwa 0618887
refactor(images): 좋아요 아이콘의 'unlike' 상태에서 테두리 색 변경 (white > #393E46)
vi-wolhwa 1f448a4
refactor(LikeWidget): 좋아요 버튼의 카운터 포멧 로직을 상위컴포넌트에서 'LikeWidget' 내부로 이동
vi-wolhwa 0ac0b88
refactor(LikeWidget): 좋아요 위젯 마우스 커서 변경(pointer) 및 import path alias
vi-wolhwa e7a4d05
refactor(LikeWidget): 좋아요 위젯의 핸들러 함수명 변경 (onLikeButtonClick > onLikeW…
vi-wolhwa bedc9b7
refactor(LikeWidget): console.log 삭제
vi-wolhwa 0957771
refactor(api): 좋아요 API 요청 실패 조건문 변경
vi-wolhwa 628e251
fix(routes): 좋아요 요청 endpoint 변경 (like > /like)
vi-wolhwa bb911ab
test(mocks): 좋아요 기능 MSW 핸들러 구현
vi-wolhwa 5586a3b
refactor(api): api/index.ts
vi-wolhwa 03124ef
feat(api): 좋아요 기능 Mutation 훅 구현
vi-wolhwa 5a83c0e
test(mocks): templateList 데이터의 작성자를 두 명으로 분리
vi-wolhwa 82f6725
feat(hooks): useLike 훅 구현
vi-wolhwa c25504b
feat(TemplatePage): 템플릿 상세 페이지에 좋아요 기능 구현
vi-wolhwa a94465c
refactor(LikeWidget): 미사용 스타일드 컴포넌트 제거
vi-wolhwa 6b33aab
test(queries): 'useTemplateQuery' 테스트에 'AuthProvider' 추가
vi-wolhwa 3bd211d
refactor(src): 변수명 변경 (likeCount > likesCount)
vi-wolhwa 0c7ae56
fix(api): 템플릿 리스트 요청 시, memberId를 QueryParam으로 보내고 있는 문제 해결
vi-wolhwa e035923
fix(api): 좋아요 API 중복된 에러 처리 조건 제거
vi-wolhwa fe598ff
refactor(images): 좋아요 아이콘 디자인 변경 (stroke, 디자인시스템)
vi-wolhwa b3d6d15
refactor(components): LikeWidget 컴포넌트 분리 (LikeCounter, LikeButton)
vi-wolhwa 46392d7
refactor(TemplatePage): 좋아요 취소 기능 낙관적 업데이트 적용
vi-wolhwa bdbc687
design(TemplatePage): 템플릿 상세 페이지 좋아요 버튼 디자인 수정
vi-wolhwa 347b276
refactor(LikeButton): 컴포넌트명이 수정되지 않았던 문제 수정
vi-wolhwa b09161e
refactor(TemplatePage): useLike 훅에서 비동기 작업, 서버 요청의 처리 순서에 따른 좋아요 상태 위…
vi-wolhwa 58362c2
design(LikeButton): 템플릿상세페이지 좋아요 버튼의 width를 유동적으로 변경
vi-wolhwa 23d2458
refactor(TemplatePage): useLike 훅에서 setLikesCount 방식 변경
vi-wolhwa File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { HttpResponse } from 'msw'; | ||
|
||
import { END_POINTS } from '@/routes'; | ||
import { LikeDeleteRequest, LikePostRequest } from '@/types'; | ||
|
||
import { customFetch } from './customFetch'; | ||
|
||
const API_URL = process.env.REACT_APP_API_URL; | ||
|
||
export const LIKE_API_URL = `${API_URL}${END_POINTS.LIKES}`; | ||
|
||
export const postLike = async ({ templateId }: LikePostRequest) => { | ||
const response = await customFetch<HttpResponse>({ | ||
method: 'POST', | ||
url: `${LIKE_API_URL}/${templateId}`, | ||
}); | ||
|
||
return response; | ||
}; | ||
|
||
export const deleteLike = async ({ templateId }: LikeDeleteRequest) => { | ||
const response = await customFetch<HttpResponse>({ | ||
method: 'DELETE', | ||
url: `${LIKE_API_URL}/${templateId}`, | ||
}); | ||
|
||
return response; | ||
}; |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { theme } from '../../style/theme'; | ||
|
||
type State = 'like' | 'unlike' | 'unClickable'; | ||
|
||
interface Props { | ||
state: State; | ||
size: number; | ||
} | ||
|
||
const LikeIcon = ({ state, size }: Props) => { | ||
const fillColor = { | ||
like: theme.color.light.analogous_primary_400, | ||
unlike: 'none', | ||
unClickable: theme.color.light.secondary_800, | ||
}[state]; | ||
|
||
const strokeColor = { | ||
like: theme.color.light.analogous_primary_400, | ||
unlike: theme.color.light.secondary_800, | ||
unClickable: theme.color.light.secondary_800, | ||
}[state]; | ||
|
||
return ( | ||
<svg width={size} height={size} viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'> | ||
<path | ||
d='M20.42 4.58045C19.9183 4.07702 19.3222 3.67758 18.6658 3.40503C18.0094 3.13248 17.3057 2.99219 16.595 2.99219C15.8842 2.99219 15.1805 3.13248 14.5241 3.40503C13.8678 3.67758 13.2716 4.07702 12.77 4.58045L12 5.36045L11.23 4.58045C10.7283 4.07702 10.1322 3.67758 9.47578 3.40503C8.81941 3.13248 8.11568 2.99219 7.40496 2.99219C6.69425 2.99219 5.99052 3.13248 5.33414 3.40503C4.67776 3.67758 4.08164 4.07702 3.57996 4.58045C1.45996 6.70045 1.32996 10.2804 3.99996 13.0004L12 21.0004L20 13.0004C22.67 10.2804 22.54 6.70045 20.42 4.58045Z' | ||
fill={fillColor} | ||
stroke={strokeColor} | ||
strokeWidth='1' | ||
strokeLinecap='round' | ||
strokeLinejoin='round' | ||
/> | ||
</svg> | ||
); | ||
}; | ||
|
||
export default LikeIcon; |
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,21 @@ | ||
import styled from '@emotion/styled'; | ||
|
||
import { theme } from '@/style/theme'; | ||
|
||
export const LikeButtonContainer = styled.button<{ isLiked: boolean }>` | ||
cursor: pointer; | ||
|
||
display: flex; | ||
gap: 0.5rem; | ||
align-items: center; | ||
justify-content: center; | ||
|
||
height: 2.5rem; | ||
padding: 0 0.75rem; | ||
|
||
color: ${({ isLiked }) => (isLiked ? theme.color.light.analogous_primary_400 : 'white')}; | ||
|
||
border: 1px solid | ||
${({ isLiked }) => (isLiked ? theme.color.light.analogous_primary_400 : theme.color.light.secondary_800)}; | ||
border-radius: 16px; | ||
`; |
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,21 @@ | ||
import { LikeIcon } from '@/assets/images'; | ||
import { Text } from '@/components'; | ||
import { theme } from '@/style/theme'; | ||
import { formatWithK } from '@/utils'; | ||
|
||
import * as S from './LikeButton.style'; | ||
|
||
interface Props { | ||
likesCount: number; | ||
isLiked: boolean; | ||
onLikeButtonClick: () => void; | ||
} | ||
|
||
const LikeButton = ({ likesCount, isLiked, onLikeButtonClick }: Props) => ( | ||
<S.LikeButtonContainer isLiked={isLiked} onClick={onLikeButtonClick}> | ||
<LikeIcon state={isLiked ? 'like' : 'unlike'} size={20} /> | ||
<Text.Medium color={theme.color.light.secondary_800}>{formatWithK(likesCount)}</Text.Medium> | ||
</S.LikeButtonContainer> | ||
); | ||
|
||
export default LikeButton; |
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,8 @@ | ||
import styled from '@emotion/styled'; | ||
|
||
export const LikeCounterContainer = styled.div` | ||
display: flex; | ||
gap: 0.75rem; | ||
align-items: center; | ||
height: 1.5rem; | ||
`; |
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,20 @@ | ||
import { LikeIcon } from '@/assets/images'; | ||
import { Text } from '@/components'; | ||
import { theme } from '@/style/theme'; | ||
import { formatWithK } from '@/utils'; | ||
|
||
import * as S from './LikeCounter.style'; | ||
|
||
interface Props { | ||
likesCount: number; | ||
isLiked: boolean; | ||
} | ||
|
||
const LikeCounter = ({ likesCount, isLiked }: Props) => ( | ||
<S.LikeCounterContainer> | ||
<LikeIcon state={isLiked ? 'like' : 'unClickable'} size={14} /> | ||
<Text.Small color={theme.color.light.secondary_800}>{formatWithK(likesCount)}</Text.Small> | ||
</S.LikeCounterContainer> | ||
); | ||
|
||
export default LikeCounter; |
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 |
---|---|---|
|
@@ -2,8 +2,8 @@ import { type LanguageName, loadLanguage } from '@uiw/codemirror-extensions-lang | |
import { quietlight } from '@uiw/codemirror-theme-quietlight'; | ||
import CodeMirror, { EditorView } from '@uiw/react-codemirror'; | ||
|
||
import { PersonIcon } from '@/assets/images'; | ||
import { Button, Flex, TagButton, Text } from '@/components'; | ||
import { ClockIcon, PersonIcon } from '@/assets/images'; | ||
import { Button, Flex, LikeCounter, TagButton, Text } from '@/components'; | ||
import { useToggle } from '@/hooks'; | ||
import { theme } from '@/style/theme'; | ||
import type { Tag, TemplateListItem } from '@/types'; | ||
|
@@ -38,16 +38,23 @@ const TemplateCard = ({ template }: Props) => { | |
<S.TemplateCardContainer data-testid='template-card'> | ||
<Flex direction='column' gap='1rem'> | ||
<Flex justify='space-between' gap='3rem'> | ||
<Flex align='center' gap='0.125rem'> | ||
<PersonIcon width={14} /> | ||
<Text.Small color={theme.mode === 'dark' ? theme.color.dark.primary_300 : theme.color.light.primary_500}> | ||
{member?.name || ''} | ||
</Text.Small> | ||
<Flex gap='0.75rem'> | ||
<Flex align='center' gap='0.25rem'> | ||
<PersonIcon width={14} /> | ||
<Text.Small color={theme.mode === 'dark' ? theme.color.dark.primary_300 : theme.color.light.primary_500}> | ||
{member.name} | ||
</Text.Small> | ||
</Flex> | ||
<Flex align='center' gap='0.25rem'> | ||
<ClockIcon width={14} /> | ||
Comment on lines
+43
to
+49
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 요 icon들 14로 거의 쓸거 같다면 기본값을 14로 해도 좋을 것 같네요! |
||
<S.NoWrapTextWrapper> | ||
<Text.Small color={theme.color.light.primary_500}>{formatRelativeTime(modifiedAt)}</Text.Small> | ||
</S.NoWrapTextWrapper> | ||
</Flex> | ||
</Flex> | ||
<Flex align='center'> | ||
<LikeCounter likesCount={template.likesCount} isLiked={template.isLiked} /> | ||
</Flex> | ||
|
||
<S.NoWrapTextWrapper> | ||
<Text.XSmall color={theme.color.light.secondary_500}>{formatRelativeTime(modifiedAt)}</Text.XSmall> | ||
</S.NoWrapTextWrapper> | ||
</Flex> | ||
|
||
<S.EllipsisTextWrapper> | ||
|
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
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Jaymyong66 @Hain-tain
변경된 API 명세에 따른 반영 (현재파일 이하 변경사항 동일)
#680
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'/login' 를 붙여야하는 히스토리를 켬미에게 들어서 참고하시라고 기술해둡니다.
[기본 전제]
[원래 상황]
[좋아요로 인해 변경된 상황]
[결론]