-
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.
- Loading branch information
Showing
62 changed files
with
4,097 additions
and
365 deletions.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
{ | ||
"extends": [ | ||
"next/core-web-vitals", | ||
"plugin:storybook/recommended" | ||
"plugin:storybook/recommended", | ||
"prettier" | ||
] | ||
} | ||
} |
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 |
---|---|---|
@@ -1,7 +1,7 @@ | ||
import { fetchToServer } from "@/utils/api"; | ||
import { serverApi } from "@/utils/api"; | ||
|
||
export async function GET() { | ||
return fetchToServer({ | ||
return serverApi({ | ||
path: "api/banners", | ||
}); | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { serverApi } from "@/utils/api"; | ||
import { NextRequest } from "next/server"; | ||
|
||
export async function PUT( | ||
request: NextRequest, | ||
context: { params: { linkBookId: string } }, | ||
) { | ||
const body = await request.json(); | ||
const linkBookId = context.params.linkBookId; | ||
|
||
return serverApi({ | ||
path: `api/link-books/${linkBookId}`, | ||
method: "PUT", | ||
body, | ||
}); | ||
} | ||
|
||
export async function DELETE( | ||
request: NextRequest, | ||
context: { params: { linkBookId: string } }, | ||
) { | ||
const linkBookId = context.params.linkBookId; | ||
|
||
return serverApi({ path: `api/link-books/${linkBookId}`, method: "DELETE" }); | ||
} |
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 |
---|---|---|
@@ -1,5 +1,15 @@ | ||
import { fetchToServer } from "@/utils/api"; | ||
import { serverApi } from "@/utils/api"; | ||
import { NextRequest } from "next/server"; | ||
|
||
export async function GET() { | ||
return fetchToServer({ path: "api/link-books" }); | ||
export async function GET(request: NextRequest) { | ||
const sort = request.nextUrl.searchParams.get("sort"); | ||
const queryString = sort && `sort=${sort}`; | ||
|
||
return serverApi({ path: "api/link-books", queryString }); | ||
} | ||
|
||
export async function POST(request: NextRequest) { | ||
const body = await request.json(); | ||
|
||
return serverApi({ path: "api/link-books", method: "POST", body }); | ||
} |
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,85 @@ | ||
"use client"; | ||
import { useSelectLinkBookStore } from "@/store/useLinkBookStore"; | ||
import clsx from "clsx"; | ||
import { useCallback } from "react"; | ||
import { useMutation, useQueryClient } from "@tanstack/react-query"; | ||
import Dialog from "@/components/dialog"; | ||
import { useOpenDialogStore } from "@/store/useDialogStore"; | ||
|
||
export default function DeleteFolderDialog() { | ||
const { deleteFolder: isOpen, openDeleteFolder: open } = useOpenDialogStore(); | ||
const { linkBook, selectLinkBook } = useSelectLinkBookStore(); | ||
|
||
const onClose = useCallback(() => { | ||
if (linkBook) { | ||
selectLinkBook(undefined); | ||
} | ||
open(false); | ||
}, [open, linkBook, selectLinkBook]); | ||
|
||
const queryClient = useQueryClient(); | ||
const remove = useMutation<{ deletedLinks: number }, Error>({ | ||
mutationFn: async () => | ||
( | ||
await fetch(`my-folder/api/${linkBook?.linkBookId}`, { | ||
method: "DELETE", | ||
}) | ||
).json(), | ||
onSuccess: () => { | ||
queryClient.setQueriesData<TQueryLinkBooks>( | ||
{ queryKey: ["linkBooks"] }, | ||
(prevLinkBooks) => { | ||
const index = prevLinkBooks!.linkBooks.findIndex( | ||
(prev) => prev.linkBookId === linkBook?.linkBookId, | ||
); | ||
return { | ||
linkBooks: [ | ||
...prevLinkBooks!.linkBooks.slice(0, index), | ||
...prevLinkBooks!.linkBooks.slice(index + 1), | ||
], | ||
totalLinkCount: prevLinkBooks!.totalLinkCount - 1, | ||
}; | ||
}, | ||
); | ||
onClose(); | ||
}, | ||
}); | ||
async function handleSubmit() { | ||
remove.mutate(); | ||
} | ||
|
||
if (!isOpen) return null; | ||
|
||
if (!linkBook?.linkBookId) { | ||
alert("해당 폴더를 찾을 수 없습니다."); | ||
return null; | ||
} | ||
|
||
return ( | ||
<Dialog open={isOpen} onCloseCallback={onClose} className="w-[421.78px]"> | ||
<div className="flex flex-col items-center gap-5"> | ||
<div className="text-center text-[#2F2F2F]"> | ||
<p>폴더 내의 모든 링크가 삭제됩니다.</p> | ||
<p>폴더를 삭제하시겠습니까?</p> | ||
</div> | ||
<div className="mt-3 flex justify-center gap-1"> | ||
<button | ||
className="h-[56px] w-[164.89px] rounded-lg bg-[#BBBBBB] font-bold text-white" | ||
onClick={onClose} | ||
> | ||
취소 | ||
</button> | ||
<button | ||
className={clsx( | ||
"h-[56px] w-[164.89px] rounded-lg font-bold text-white", | ||
"bg-primary", | ||
)} | ||
onClick={handleSubmit} | ||
> | ||
삭제 | ||
</button> | ||
</div> | ||
</div> | ||
</Dialog> | ||
); | ||
} |
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,73 @@ | ||
import { useClearDropdown } from "@/hooks/clear-dropdown"; | ||
import { useOpenDialogStore } from "@/store/useDialogStore"; | ||
import Image from "next/image"; | ||
import { useState } from "react"; | ||
import { LinkBook } from "../type"; | ||
import { useSelectLinkBookStore } from "@/store/useLinkBookStore"; | ||
|
||
type DropdownItemProps = { | ||
title: string; | ||
handleClick: () => void; | ||
}; | ||
|
||
const DropdownItem = ({ title, handleClick }: DropdownItemProps) => { | ||
return ( | ||
<button | ||
onClick={handleClick} | ||
className="w-full px-5 py-1 font-semibold text-[#1D1D1D]" | ||
> | ||
{title} | ||
</button> | ||
); | ||
}; | ||
|
||
type InputProps = { | ||
linkBook: LinkBook; | ||
}; | ||
|
||
const DropdownMore = ({ linkBook }: InputProps) => { | ||
const [isOpen, setIsOpen] = useState(false); | ||
|
||
const onClose = () => setIsOpen(false); | ||
|
||
const ref = useClearDropdown(onClose); | ||
|
||
const { openMutateFolder, openDeleteFolder } = useOpenDialogStore(); | ||
const { selectLinkBook } = useSelectLinkBookStore(); | ||
|
||
const handleModify = () => { | ||
selectLinkBook(linkBook); | ||
openMutateFolder(true); | ||
onClose(); | ||
}; | ||
const handleDelete = () => { | ||
selectLinkBook(linkBook); | ||
openDeleteFolder(true); | ||
onClose(); | ||
}; | ||
|
||
return ( | ||
<div className="relative" data-testid="link-book-more" ref={ref}> | ||
<button | ||
onClick={() => setIsOpen(true)} | ||
className="flex h-12 w-12 items-center justify-center rounded-full bg-black" | ||
> | ||
<Image | ||
src="/icons/icon-more-vertical.png" | ||
alt="more" | ||
width={26.4} | ||
height={26.4} | ||
/> | ||
</button> | ||
|
||
{isOpen && ( | ||
<div className="absolute z-10 mt-1 flex w-[110px] flex-col rounded-lg border border-background-secondary bg-white py-4 shadow-lg"> | ||
<DropdownItem title="폴더 수정" handleClick={handleModify} /> | ||
<DropdownItem title="폴더 삭제" handleClick={handleDelete} /> | ||
</div> | ||
)} | ||
</div> | ||
); | ||
}; | ||
|
||
export default DropdownMore; |
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,61 @@ | ||
"use client"; | ||
import { useClearDropdown } from "@/hooks/clear-dropdown"; | ||
import clsx from "clsx"; | ||
import Image from "next/image"; | ||
import { useEffect, useRef, useState } from "react"; | ||
|
||
export const sortOptions = [ | ||
{ label: "생성순", value: "created_at" }, | ||
{ label: "제목순", value: "title" }, | ||
{ label: "업데이트순", value: "last_saved_at" }, | ||
]; | ||
|
||
type InputProps = { | ||
selected: string; | ||
setSelected: (option: string) => void; | ||
}; | ||
|
||
const DropdownSort = ({ selected, setSelected }: InputProps) => { | ||
const [isOpen, setIsOpen] = useState(false); | ||
|
||
const ref = useClearDropdown(() => setIsOpen(false)); | ||
|
||
const selectedOption = sortOptions.find(({ value }) => selected === value); | ||
return ( | ||
<div className="relative" data-testid="link-book-list-sort" ref={ref}> | ||
<button | ||
data-testid="open-button" | ||
onClick={() => setIsOpen(!isOpen)} | ||
className="flex h-[24px] items-center p-1 font-semibold text-text-secondary" | ||
> | ||
<div>{selectedOption?.label}</div> | ||
<Image src="/icons/icon-down2.png" alt="down" width={24} height={24} /> | ||
</button> | ||
|
||
{isOpen && ( | ||
<div className="absolute right-0 z-10 mt-1 flex min-w-32 flex-col rounded-lg border border-background-secondary bg-white py-4 shadow-lg"> | ||
{sortOptions.map((item) => ( | ||
<button | ||
data-testid={`dropdown-${item.label}`} | ||
key={item.value} | ||
onClick={() => { | ||
setSelected(item.value); | ||
setIsOpen(false); | ||
}} | ||
className={clsx( | ||
"w-full px-5 py-1 text-start", | ||
selected === item.value | ||
? "font-bold text-[#1D1D1D]" | ||
: "text-text-secondary", | ||
)} | ||
> | ||
{item.label} | ||
</button> | ||
))} | ||
</div> | ||
)} | ||
</div> | ||
); | ||
}; | ||
|
||
export default DropdownSort; |
Oops, something went wrong.