-
Notifications
You must be signed in to change notification settings - Fork 51
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
[이정윤] week20 #561
The head ref may contain hidden characters: "part3-\uC774\uC815\uC724-week20"
[이정윤] week20 #561
Changes from all commits
42ef829
5359819
000b966
ec0030a
74ad933
e20bb4e
b12214f
be7cdab
325439b
8997efa
1166965
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
interface LinksData { | ||
export interface LinksData { | ||
data: Link[]; | ||
} | ||
interface Link { | ||
export interface Link { | ||
id: number; | ||
created_at: string; | ||
updated_at: null; | ||
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. updated_at이 무조건 null이라면 굳이 타입으로 지정하지 않으셔도 됩니다. |
||
|
@@ -12,8 +12,9 @@ interface Link { | |
folder_id: number; | ||
} | ||
|
||
interface FolderLink { | ||
export interface FolderLink { | ||
id: number; | ||
favorite: boolean; | ||
created_at: string; | ||
url: string; | ||
title: string; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import Image from "next/image"; | ||
|
||
import styles from "./CardItem.module.css"; | ||
|
||
import starOnImg from "@/assets/images/star-on.svg"; | ||
import starOffImg from "@/assets/images/star-off.svg"; | ||
import { useMutation, useQueryClient } from "@tanstack/react-query"; | ||
import fetcher from "@/lib/axios"; | ||
import { UserFolders } from "@/@types/folder.types"; | ||
|
||
interface FolderPageCardItemProps { | ||
isFavorite: boolean; | ||
linkId: number; | ||
} | ||
|
||
function CardFavoriteButton({ isFavorite, linkId }: FolderPageCardItemProps) { | ||
const queryClient = useQueryClient(); | ||
|
||
const toggleFavoriteMutation = useMutation({ | ||
mutationFn: async () => { | ||
const response = await fetcher<UserFolders[]>({ | ||
url: `/links/${linkId}`, | ||
method: "put", | ||
data: { favorite: !isFavorite }, | ||
}); | ||
return response.data; | ||
}, | ||
Comment on lines
+20
to
+27
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. api 요청하는 함수는 따로 작성해서 파일로 관리하셔도 좋습니다. |
||
onSuccess: () => { | ||
queryClient.invalidateQueries({ queryKey: ["links"] }); | ||
queryClient.invalidateQueries({ queryKey: ["links", "all"] }); | ||
}, | ||
onError: (error) => { | ||
const errorResponse = (error as any).response; | ||
window.alert(errorResponse?.data.message); | ||
}, | ||
}); | ||
|
||
const handleButtonClick = () => { | ||
toggleFavoriteMutation.mutate(); | ||
}; | ||
return ( | ||
<button className={styles.bookmarkButton} onClick={handleButtonClick}> | ||
<Image src={isFavorite ? starOnImg : starOffImg} alt="즐겨찾기 이미지" /> | ||
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. next/Image 사용하실때 크기 지정도 해주셔야합니다! |
||
</button> | ||
); | ||
} | ||
|
||
export default CardFavoriteButton; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,8 @@ import { ReactNode } from "react"; | |
import FolderPageCardItem from "./FolderPageCardItem"; | ||
import { formatDate, getTimeDiff, prettyFormatTimeDiff } from "@/utils/utils"; | ||
import SharedPageCardItem from "./SharedPageCardItem"; | ||
import { FolderLink } from "@/@types/link.types"; | ||
import { UserFolders } from "@/@types/folder.types"; | ||
|
||
interface CardListProps { | ||
type: "folder" | "shared"; | ||
|
@@ -17,7 +19,15 @@ function CardList({ | |
return ( | ||
LinksData && | ||
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. 카멜케이스로 작성해주시면 좋을 것 같고, folderListData 처럼 linksData?: FolderLink[]로 작성해주셔도 좋을 것 같습니다. |
||
LinksData.map((link) => { | ||
const { id, created_at, url, title, description, image_source } = link; | ||
const { | ||
id, | ||
created_at, | ||
url, | ||
title, | ||
description, | ||
image_source, | ||
favorite, | ||
} = link; | ||
|
||
const formattedCreatedAt = formatDate(created_at); | ||
const timeDiff = getTimeDiff(created_at); | ||
|
@@ -28,6 +38,7 @@ function CardList({ | |
<FolderPageCardItem | ||
key={url} | ||
id={id} | ||
favorite={favorite} | ||
folderListData={folderListData} | ||
formatTimeDiff={formatTimeDiff} | ||
formattedCreatedAt={formattedCreatedAt} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,7 @@ import ModalButton from "../ModalButton/ModalButton"; | |
import Image from "next/image"; | ||
import fetcher from "@/lib/axios"; | ||
import { useSetFolderId } from "@/contexts/UserContext"; | ||
import { UserFolders } from "@/@types/folder.types"; | ||
|
||
interface Props { | ||
inputValue: string; | ||
|
@@ -74,23 +75,28 @@ function AddLinkModalContent({ inputValue, folderListData, onClose }: Props) { | |
<p className={styles.link}>{inputValue}</p> | ||
</div> | ||
<div className={styles.optionsContainer}> | ||
{folderListDataArray?.map((folder) => ( | ||
<div | ||
className={classNames( | ||
styles.optionContainer, | ||
selectedFolder === folder && styles.selected | ||
)} | ||
key={folder.id} | ||
id={folder.name} | ||
onClick={() => handleCheckClick(folder)} | ||
> | ||
<div className={styles.option}> | ||
<h2>{folder.name}</h2> | ||
<p>{`${folder?.link_count}개 링크`}</p> | ||
{folderListDataArray?.map((folder) => { | ||
if (folder.name === "⭐️ 즐겨찾기") return; | ||
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. 폴더명을 검사하는 로직은 조금 위험해보이긴 합니다. 어쩔 수 없는 경우라면 폴더명을 상수로 관리하시면 좋을 것 같습니다. |
||
return ( | ||
<div | ||
className={classNames( | ||
styles.optionContainer, | ||
selectedFolder === folder && styles.selected | ||
)} | ||
key={folder.id} | ||
id={folder.name} | ||
onClick={() => handleCheckClick(folder)} | ||
> | ||
<div className={styles.option}> | ||
<h2>{folder.name}</h2> | ||
<p>{`${folder?.link_count}개 링크`}</p> | ||
Comment on lines
+91
to
+92
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. 위에는 folder.name이고 아래는 folder?.link_count 인데, folder가 nullable 하다면 둘다 ?를 붙여주시는게 좋아보입니다. |
||
</div> | ||
{selectedFolder === folder && ( | ||
<Image src={checkImg} alt="check" /> | ||
)} | ||
</div> | ||
{selectedFolder === folder && <Image src={checkImg} alt="check" />} | ||
</div> | ||
))} | ||
); | ||
})} | ||
</div> | ||
<ModalButton color="blue" onClick={handleAddLink}> | ||
추가하기 | ||
|
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.
boolean 타입이기 때문에 isFavorite 같은 변수명도 괜찮을 것 같습니다. 혹시 api 명세서에 나온 내용이라면 그냥 냅두셔도 좋습니다.