Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions components/Dropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from "react";

interface DropdownProps {
isDropdownOpen: boolean;
onEdit: () => void;
openDelete: () => void;
}

const Dropdown = ({ isDropdownOpen, onEdit, openDelete }: DropdownProps) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isDropdownOpen은 어떤 용도 인가요 ?.?
따로 쓰여지고 있지는 않는거 같아서요 !

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

modal 열림 상태일 때 상태 변경하려고 사용했는데 useModalStore에서 isOpen 상태를 가져와 isModalOpen에 저장하도록 변경했습니다!

const buttonStyle =
"block w-full py-2 text-sm hover:bg-gray200 hover:text-purple100";

return (
<div className="absolute top-[17px] right-0 flex flex-col gap-[2px] min-w-[100px] bg-white shadow-lg rounded">
<button className={buttonStyle} onClick={onEdit}>
수정하기
</button>
<button className={buttonStyle} onClick={openDelete}>
삭제하기
</button>
</div>
);
};

export default Dropdown;
144 changes: 83 additions & 61 deletions components/LinkCard.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useState } from "react";
import timeAgo from "@/util/timAgo";
import Image from "next/image";
import Dropdown from "./Dropdown";

interface linkDataType {
id: number;
Expand All @@ -13,77 +14,98 @@ interface linkDataType {
}

interface CardItemProps extends linkDataType {
onEdit: () => void;
openDelete: () => void;
isFavoritePage?: boolean; // 즐겨찾기 페이지 여부를 판별하는 flag
}

const LinkCard = ({ isFavoritePage, ...info }: CardItemProps) => {
const LinkCard = ({
onEdit,
openDelete,
isFavoritePage,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prop으로 받지 않고 const isFavoritePage = router.pathname === '/favorite'; 라는 식의 코드를 안에서 처리해주면 어떨까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네 수정하겠습니다!

...info
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제가 링크 페이지 PR 올리면서 고쳐놓긴 했는데 ...info로 적어주면 링크데이터 객체 값을 하나하나 명시해주겠다는 의미인데! 그러면 LinkCard 컴포넌트를 리턴할때마다 코드가 엄청 길어집니다! map으로 돌릴때 el 요소를 그냥 info에 넣어주는게 전 더 깔끔한 것 같아요!

}: CardItemProps) => {
const [isSubscribed, setIsSubscribed] = useState(false);
const [isOpen, setIsOpen] = useState(false);
const [isDropdownOpen, setIsDropdownOpen] = useState(false);

const formattedDate = info.createdAt?.slice(0, 10).replace(/-/g, ".");
const createdTime = timeAgo(info.createdAt);

// dropdown 버튼
const toggleDropdown = () => setIsDropdownOpen((prev) => !prev);

return (
<div className="w-[340px] h-[344px] rounded-[12px] shadow-lg overflow-hidden cursor-pointer hover:scale-105 hover:duration-300">
<section className="relative w-full h-[60%]">
<Image
src={info.imageSource || `/images/no-content.svg`}
className="object-cover"
alt="링크 미리보기"
fill
/>
{/* isFavoritePage가 false일 때만 즐겨찾기 버튼 렌더링 */}
{!isFavoritePage &&
(isSubscribed ? (
<div
onClick={() => setIsSubscribed(!isSubscribed)}
className="absolute top-[15px] right-[15px] z-1"
>
<Image
src="/icons/star-fill.svg"
width={32}
height={32}
alt="subscripe button"
/>
</div>
) : (
<div
onClick={() => setIsSubscribed(!isSubscribed)}
className="absolute top-[15px] right-[15px] z-1"
>
<Image
src="/icons/star-empty.svg"
width={32}
height={32}
alt="subscripe button"
/>
</div>
))}
</section>
<>
<div className="w-[340px] h-[344px] rounded-[12px] shadow-lg overflow-hidden cursor-pointer hover:scale-105 hover:duration-300">
<section className="relative w-full h-[60%]">
<Image
src={info.imageSource || `/images/no-content.svg`}
className="object-cover"
alt="링크 미리보기"
fill
/>
{/* isFavoritePage가 false일 때만 즐겨찾기 버튼 렌더링 */}
{!isFavoritePage &&
(isSubscribed ? (
<div
onClick={() => setIsSubscribed(!isSubscribed)}
className="absolute top-[15px] right-[15px] z-1"
>
<Image
src="/icons/star-fill.svg"
width={32}
height={32}
alt="subscripe button"
/>
</div>
) : (
<div
onClick={() => setIsSubscribed(!isSubscribed)}
className="absolute top-[15px] right-[15px] z-1"
>
<Image
src="/icons/star-empty.svg"
width={32}
height={32}
alt="subscripe button"
/>
</div>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isSubscribded에 따라 이미지만 바뀌니
src={isSubscribed ? "/icons/star-fill.svg" : "/icons/star-empty.svg"} 한줄로 분기처리하면 더 깔끔할거 같습니다 !

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 저도 이거 신경쓰였는데 이런 방법이👍👍

))}
</section>

<section className="w-full h-[40%] flex flex-col justify-between gap-[10px] pt-[15px] px-[20px] pb-[10px]">
<div className="flex justify-between">
<span className="text-sm text-gray-400">
{createdTime || "1일 전"}
</span>
{/* isFavoritePage가 false일 때만 케밥 버튼 렌더링 */}
{!isFavoritePage && (
<div
className="relative w-[21px] h-[17px]"
onClick={(state) => setIsOpen(!state)}
>
<Image src="/icons/kebab.svg" alt="kebab button" fill />
</div>
)}
</div>
<div className="text-[black100] text-lg ">
{info.description || "설명"}
</div>
<div className="text-sm text-[black200]">
{formattedDate || "2024.11.06"}
</div>
</section>
</div>
<section className="w-full h-[40%] flex flex-col justify-between gap-[10px] pt-[15px] px-[20px] pb-[10px]">
<div className="flex justify-between">
<span className="text-sm text-gray-400">
{createdTime || "1일 전"}
</span>
{/* isFavoritePage가 false일 때만 케밥 버튼 렌더링 */}
{!isFavoritePage && (
<div className="relative">
<button
className="relative w-[21px] h-[17px]"
onClick={toggleDropdown}
>
<Image src="/icons/kebab.svg" alt="kebab button" fill />
</button>
{isDropdownOpen && (
<Dropdown
isDropdownOpen={isDropdownOpen}
onEdit={onEdit}
openDelete={openDelete}
/>
)}
</div>
)}
</div>
<div className="text-[black100] text-lg ">
{info.description || "설명"}
</div>
<div className="text-sm text-[black200]">
{formattedDate || "2024.11.06"}
</div>
</section>
</div>
</>
);
};

Expand Down
2 changes: 1 addition & 1 deletion components/modal/AddFolderModal.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ChangeEvent, useState } from "react";
import { postFolders } from "@/lib/api/folder";
import ModalContainer from "./modalComponents/ModalContainer";
import ModalInput from "./modalComponents/ModalInput";
import { postFolders } from "@/lib/api/folder";
import useModalStore from "@/store/useModalStore";
import SubmitButton from "../SubMitButton";

Expand Down
26 changes: 23 additions & 3 deletions components/modal/DeleteLinkModal.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,34 @@
import useModalStore from "@/store/useModalStore";
import SubmitButton from "../SubMitButton";
import ModalContainer from "./modalComponents/ModalContainer";
import { useLinkCardStore } from "@/store/useLinkCardStore";

const DeleteLinkModal = ({
link,
linkId,
}: {
link: string;
linkId: number;
}) => {
const { closeModal } = useModalStore();
const { deleteLink } = useLinkCardStore();

const handleDelete = async () => {
try {
await deleteLink(linkId);
closeModal();
} catch (error) {
console.error("Failed to delete the link:", error);
}
};

const DeleteLinkModal = ({ link }: { link: string }) => {
return (
<ModalContainer title="링크 삭제" subtitle={link}>
<SubmitButton
type="button"
// onClick={handleSubmit}
onClick={handleDelete}
width="w-full"
height="h-[51px] "
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

모달 파일마다 공백이 있었더라구요 😅👍

height="h-[51px]"
color="negative"
>
삭제하기
Expand Down
55 changes: 55 additions & 0 deletions components/modal/EditLink.tsx
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

안그래도 요걸 제가 안만들어놨었는데 추가해주셨군요!👍

Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { ChangeEvent, useState } from "react";
import { putLinkURL } from "@/lib/api/link";
import { useLinkCardStore } from "@/store/useLinkCardStore";
import ModalContainer from "./modalComponents/ModalContainer";
import ModalInput from "./modalComponents/ModalInput";
import useModalStore from "@/store/useModalStore";
import SubmitButton from "../SubMitButton";

const EditLink = ({
folderName,
link,
linkId,
}: {
folderName: string;
link: string;
linkId: number;
}) => {
const [value, setValue] = useState("");
const { closeModal } = useModalStore();
const { updateLink } = useLinkCardStore();

const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
setValue(e.target.value);
};

const handleSubmit = async () => {
const body = {
url: value,
};
if (value !== "") {
await updateLink(linkId, body);
}
closeModal();
};
return (
<ModalContainer title="링크 주소 변경">
<ModalInput
placeholder={link}
name={folderName}
value={value}
onChange={handleChange}
/>
<SubmitButton
type="button"
onClick={handleSubmit}
width="w-full"
height="h-[51px] "
color="positive"
>
변경하기
</SubmitButton>
</ModalContainer>
);
};
export default EditLink;
17 changes: 16 additions & 1 deletion components/modal/modalManager/ModalManager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import AddFolderModal from "../AddFolderModal";
import DeleteLinkModal from "../DeleteLinkModal";
import EditModal from "../EditModal";
import SNSModal from "../SNSModal";
import EditLink from "../EditLink";

export const ModalType = {
AddFolderModal: "AddFolderModal",
Expand All @@ -13,6 +14,7 @@ export const ModalType = {
DeleteLinkModal: "DeleteLinkModal",
EditModal: "EditModal",
SNSModal: "SNSModal",
EditLink: "EditLink",
} as const;

export type ModalKeysType = keyof typeof ModalType;
Expand Down Expand Up @@ -42,10 +44,23 @@ export const Modal = () => {
case "DeleteFolderModal":
return <DeleteFolderModal folderName={props.folderName || "폴더이름"} />;
case "DeleteLinkModal":
return <DeleteLinkModal link={props.link || "링크"} />;
return (
<DeleteLinkModal
link={props.link || "링크"}
linkId={Number(props.linkId)}
/>
);
case "EditModal":
return <EditModal folderName={props.folderName || "폴더이름"} />;
case "SNSModal":
return <SNSModal folderName={props.folderName || "폴더이름"} />;
case "EditLink":
return (
<EditLink
folderName={props.folderName || "폴더이름"}
link={props.link || "링크"}
linkId={Number(props.linkId)}
/>
);
}
};
Loading
Loading