Skip to content

Commit f0f1640

Browse files
committed
Merge branch 'dev' of https://github.com/FE9-2/workroot into design/landing-fix
2 parents 272d98f + 17a34fd commit f0f1640

File tree

9 files changed

+98
-12
lines changed

9 files changed

+98
-12
lines changed

src/app/(pages)/mypage/components/sections/CommentsSection.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import ContentSection from "@/app/components/layout/ContentSection";
99
import useWidth from "@/hooks/useWidth";
1010
import ScrollTopButton from "@/app/components/button/default/ScrollTopButton";
1111
import SamllLoadingSpinner from "@/app/components/loading-spinner/SmallLoadingSpinner";
12+
import LoadingSpinner from "@/app/components/loading-spinner/LoadingSpinner";
1213

1314
export default function CommentsSection() {
1415
const [currentPage, setCurrentPage] = useState(1);
@@ -43,6 +44,10 @@ export default function CommentsSection() {
4344
window.scrollTo(0, 0);
4445
};
4546

47+
if (isLoading) {
48+
return <LoadingSpinner />;
49+
}
50+
4651
if (error) {
4752
return (
4853
<div className="flex h-[calc(100vh-300px)] items-center justify-center">

src/app/(pages)/mypage/components/sections/PostsSection.tsx

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import ScrollTopButton from "@/app/components/button/default/ScrollTopButton";
1111
import BoardPostItem from "@/app/components/card/board/BoardPostItem";
1212
import DotLoadingSpinner from "@/app/components/loading-spinner/DotLoadingSpinner";
1313
import SamllLoadingSpinner from "@/app/components/loading-spinner/SmallLoadingSpinner";
14+
import LoadingSpinner from "@/app/components/loading-spinner/LoadingSpinner";
15+
import { useUser } from "@/hooks/queries/user/me/useUser";
1416

1517
export default function PostsSection() {
1618
const { orderBy } = useMySortStore();
@@ -36,7 +38,7 @@ export default function PostsSection() {
3638
limit: postsPerPage,
3739
orderBy: orderBy.posts,
3840
});
39-
41+
const { user } = useUser();
4042
useEffect(() => {
4143
if (inView && hasNextPage && !isFetchingNextPage) {
4244
fetchNextPage();
@@ -51,6 +53,10 @@ export default function PostsSection() {
5153
);
5254
}
5355

56+
if (isLoading) {
57+
return <LoadingSpinner />;
58+
}
59+
5460
return (
5561
<div className="flex flex-col items-center">
5662
{/* 메인 콘텐츠 영역 */}
@@ -70,7 +76,13 @@ export default function PostsSection() {
7076
{data.pages.map((page) => (
7177
<React.Fragment key={page.nextCursor}>
7278
{page.data.map((post) => (
73-
<BoardPostItem post={post} key={post.id} />
79+
<BoardPostItem
80+
post={post}
81+
key={post.id}
82+
isAuthor={!!(post.writer.id === user?.id)}
83+
limit={postsPerPage}
84+
orderBy={orderBy.posts}
85+
/>
7486
))}
7587
</React.Fragment>
7688
))}

src/app/(pages)/mypage/page.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@ import CommentsSection from "./components/sections/CommentsSection";
66
import ScrapsSection from "./components/sections/ScrapsSection";
77
import { userRoles } from "@/constants/userRoles";
88
import { useUser } from "@/hooks/queries/user/me/useUser";
9+
import toast from "react-hot-toast";
10+
import { useRouter } from "next/navigation";
911

1012
export default function MyPage() {
1113
const searchParams = useSearchParams();
1214
const currentTab = searchParams.get("tab") || "posts";
15+
const router = useRouter();
1316
const { user } = useUser();
1417
const isApplicant = user?.role === userRoles.APPLICANT;
1518

@@ -19,5 +22,10 @@ export default function MyPage() {
1922
...(isApplicant && { scrap: <ScrapsSection /> }),
2023
}[currentTab];
2124

25+
if (!user) {
26+
toast.error("로그인이 필요한 페이지입니다.");
27+
router.push("/login");
28+
}
29+
2230
return TabContent;
2331
}

src/app/components/button/dropdown/KebabDropdown.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,14 @@ const KebabDropdown = ({ options, className = "" }: KebabDropdownProps) => {
2929
<div ref={dropdownRef} className={cn("relative inline-block text-left", className)}>
3030
<button
3131
type="button"
32-
onClick={() => setIsOpen(!isOpen)}
33-
className="rounded-full hover:bg-grayscale-50"
32+
onClick={(e) => {
33+
setIsOpen(!isOpen);
34+
e.stopPropagation();
35+
}}
36+
className="rounded-full transition-transform hover:scale-125 hover:bg-grayscale-50"
3437
aria-label="메뉴 더보기"
3538
>
36-
<BsThreeDotsVertical className="text-sm text-grayscale-200 lg:text-xl" />
39+
<BsThreeDotsVertical className="text-md text-grayscale-200 lg:text-xl" />
3740
</button>
3841

3942
{isOpen && (
@@ -42,7 +45,8 @@ const KebabDropdown = ({ options, className = "" }: KebabDropdownProps) => {
4245
<button
4346
type="button"
4447
key={`${index}-${option.label}`}
45-
onClick={() => {
48+
onClick={(e) => {
49+
e.stopPropagation();
4650
option.onClick();
4751
setIsOpen(false);
4852
}}

src/app/components/card/board/BoardComment.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ const BoardComment = ({
6767

6868
return (
6969
<Link href={`work-talk/${postId}`}>
70-
<div className="relative flex h-[202px] w-[327px] flex-col gap-2 rounded-[16px] border border-line-200 bg-grayscale-50 p-6 shadow-md md:w-[600px] lg:h-[264px] lg:w-full">
70+
<div className="relative flex h-[202px] w-[327px] flex-col gap-2 rounded-[16px] border border-line-200 bg-grayscale-50 p-6 shadow-md transition-transform hover:scale-105 md:w-[600px] lg:h-[264px] lg:w-full">
7171
{/* Post Section */}
7272
<div className="flex w-full flex-col gap-4 border-b border-line-100 pb-2 lg:pb-4">
7373
<div className="flex items-center gap-[6px] lg:gap-2">

src/app/components/card/board/BoardPostItem.tsx

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,71 @@
1+
"use client";
12
import { PostListType } from "@/types/response/post";
23
import { formatLocalDate } from "@/utils/workDayFormatter";
34
import Image from "next/image";
45
import Link from "next/link";
6+
import KebabDropdown from "../../button/dropdown/KebabDropdown";
7+
import { useRouter } from "next/navigation";
8+
import useModalStore from "@/store/modalStore";
9+
import { useDeleteComment } from "@/hooks/queries/post/comment/useDeleteComment";
10+
import { useQueryClient } from "@tanstack/react-query";
11+
12+
const BoardPostItem = ({
13+
post,
14+
isAuthor,
15+
limit,
16+
orderBy,
17+
}: {
18+
post: PostListType;
19+
isAuthor: boolean;
20+
limit: number;
21+
orderBy: string;
22+
}) => {
23+
const router = useRouter();
24+
const deleteComment = useDeleteComment(String(post.id));
25+
const queryClient = useQueryClient();
26+
const { openModal, closeModal } = useModalStore();
27+
28+
const handleDelete = () => {
29+
openModal("customForm", {
30+
isOpen: true,
31+
title: "게시글을 삭제할까요?",
32+
content: "삭제된 게시글은 복구할 수 없습니다.",
33+
confirmText: "삭제하기",
34+
cancelText: "취소",
35+
onConfirm: () => {
36+
deleteComment.mutate(undefined, {
37+
onSuccess: async () => {
38+
await queryClient.invalidateQueries({ queryKey: ["post"] });
39+
await queryClient.invalidateQueries({ queryKey: ["myPosts", { limit, orderBy }] });
40+
closeModal();
41+
},
42+
});
43+
},
44+
onCancel: () => {
45+
closeModal();
46+
},
47+
});
48+
};
49+
50+
const dropdownOptions = [
51+
{
52+
label: "수정하기",
53+
onClick: () => router.push(`/work-talk/${post.id}/edit`),
54+
},
55+
{
56+
label: "삭제하기",
57+
onClick: handleDelete,
58+
},
59+
];
560

6-
const BoardPostItem = ({ post }: { post: PostListType }) => {
761
return (
862
<Link
963
href={`/work-talk/${post.id}`}
1064
className="block cursor-pointer transition-transform duration-300 hover:scale-[1.02]"
1165
>
1266
<div className="relative flex h-[202px] min-w-[327px] flex-col justify-between rounded-[16px] border border-line-200 bg-grayscale-50 p-6 shadow-md md:w-[600px] lg:h-[264px] lg:w-full">
1367
<div className="flex flex-col gap-2">
14-
<h3 className="text-[16px] font-semibold text-black-400 lg:text-[20px]">{post.title}</h3>
68+
<h3 className="line-clamp-1 text-[16px] font-semibold text-black-400 lg:text-[20px]">{post.title}</h3>
1569
<p className="line-clamp-3 overflow-hidden text-[14px] text-grayscale-500 lg:text-[18px]">{post.content}</p>
1670
</div>
1771

@@ -48,6 +102,9 @@ const BoardPostItem = ({ post }: { post: PostListType }) => {
48102
</div>
49103
</div>
50104
</div>
105+
<div className="absolute right-3 top-6 size-9 bg-white text-center" onClick={(e) => e.stopPropagation()}>
106+
{isAuthor && <KebabDropdown options={dropdownOptions} />}
107+
</div>
51108
</div>
52109
</Link>
53110
);

src/app/components/card/cardList/AlbaListItem.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ const AlbaListItem = ({
195195
<BsThreeDotsVertical className="h-6 w-6" />
196196
</button>
197197
{showDropdown && (
198-
<div className="absolute right-0 top-8 z-10 w-32 rounded-lg border border-grayscale-200 bg-white py-2 shadow-lg">
198+
<div className="absolute right-0 top-8 z-10 w-32 overflow-hidden rounded-lg border border-grayscale-200 bg-white shadow-lg">
199199
{isApplicant ? (
200200
<>
201201
<button

src/app/components/card/cardList/apply/MyApplicationListItem.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ const MyApplicationListItem = ({ createdAt, status, resumeId, resumeName, form }
5353
</div>
5454

5555
{/* 공고 제목 */}
56-
<div className="text-grayscale-900 text-lg font-bold md:text-xl">{form.title}</div>
56+
<div className="text-grayscale-900 line-clamp-1 text-lg font-bold md:text-xl">{form.title}</div>
5757

5858
{/* 공고 설명 (2줄 제한) */}
5959
<p className="text-grayscale-600 line-clamp-2 h-[48px] text-sm md:line-clamp-2 md:text-base">

src/app/stories/design-system/components/card/cardList/BoardPostItem.stories.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,5 @@ const post = {
2929
createdAt: new Date(),
3030
};
3131
export const Default: Story = {
32-
args: { post },
32+
args: { post, isAuthor: true, limit: 10, orderBy: "최신순" },
3333
};

0 commit comments

Comments
 (0)