Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
113dc0a
Merge branch 'develop' of https://github.com/Cowokers-team/coworkes i…
huuitae Nov 26, 2025
a008777
Merge branch 'develop' into fix/my-history
huuitae Nov 26, 2025
e27ae4e
fix: 랜딩 페이지 버튼 링크 수정
huuitae Nov 26, 2025
589d010
refactor : 할 일 상세 댓글, 자유게시판 게시글 댓글 기능 로직 개선
junye0l Nov 26, 2025
255bb82
refactor : 의도에 맞는 메서드명으로 수정
junye0l Nov 26, 2025
880e983
refactor : 불필요한 오류로직 제거
junye0l Nov 26, 2025
b7dc7c9
chore : 코드 스타일 수정
junye0l Nov 26, 2025
a571078
refactor : 이벤트 핸들러 이름 수정
junye0l Nov 26, 2025
d46950c
[#171] 할 일 상세 페이지 댓글 수정,삭제 기능 작업
junye0l Nov 26, 2025
5f6c22a
fix: 할 일 목록 선택시 반응 느린 부분 수정
huuitae Nov 26, 2025
e947937
refactor : 게시글 상세 페이지 스타일 수정
junye0l Nov 26, 2025
81a3373
fix: 모달 백드롭 클릭시 이벤트 버블링 방지 추가
huuitae Nov 26, 2025
df685c9
Merge branch 'develop' of https://github.com/Cowokers-team/coworkes i…
huuitae Nov 26, 2025
7f9e8a2
Merge branch 'develop' into fix/my-history
huuitae Nov 26, 2025
ed8fd17
feat: editteam 스켈레톤 UI 추가
JinHyuk-Kim66 Nov 26, 2025
4c89526
feat: 할 일 추가, 변경 시 로딩스피너, 토스트 추가
JinHyuk-Kim66 Nov 26, 2025
3c4f79b
feat: 팀 정보 수정, 삭제시 로딩 스피너, 토스트 추가
JinHyuk-Kim66 Nov 26, 2025
124a18b
feat: 팀페이지 스켈레톤 UI 수정
JinHyuk-Kim66 Nov 26, 2025
17a0879
feat: 팀페이지 배너 통일 및 팀 나가기 기능 구현
JinHyuk-Kim66 Nov 26, 2025
ab12abe
feat: 할 일 목록 삭제, 수정 에러시 토스트로 메세지 표출
JinHyuk-Kim66 Nov 26, 2025
231845f
refactor : 게시글 작성 페이지 디자인 속성 수정
junye0l Nov 26, 2025
b8260ab
design: 스켈레톤 UI 에 radius 추가
JinHyuk-Kim66 Nov 26, 2025
9210608
Merge pull request #174 from Part-4-1/feat/additional-QA
JinHyuk-Kim66 Nov 26, 2025
8d8e674
refactor : 계정 설정 페이지 누락 디자인 속성 추가
junye0l Nov 26, 2025
3d58354
Merge branch 'develop' into refactor/pages
junye0l Nov 26, 2025
4cb22b3
design: 스켈레톤 UI radius 추가
huuitae Nov 26, 2025
9743618
Merge branch 'develop' of https://github.com/Cowokers-team/coworkes i…
huuitae Nov 26, 2025
703faee
Merge branch 'develop' into fix/my-history
huuitae Nov 26, 2025
6910df5
refactor : 게시글 수정 페이지 디자인 수정
junye0l Nov 26, 2025
e11e008
Merge pull request #175 from Part-4-1/fix/my-history
huuitae Nov 26, 2025
742da87
Merge branch 'develop' into refactor/pages
junye0l Nov 26, 2025
fe3cdde
[#x] 담당 페이지 디자인 수정
junye0l Nov 26, 2025
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
9 changes: 9 additions & 0 deletions src/app/[groupId]/_components/team-banner-members.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Member } from "@/types/members";

interface TeamBannerMembersProps {
members: Member[];
}

const TeamBannerMembers = () => {};

export default TeamBannerMembers;
44 changes: 37 additions & 7 deletions src/app/[groupId]/_components/team-body/team-body.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import useDeleteTaskList from "@/hooks/api/task/use-delete-task-list";
import usePatchTaskList from "@/hooks/api/task/use-patch-task-list";
import usePostTaskList from "@/hooks/api/task/use-post-task-list";
import usePrompt from "@/hooks/use-prompt";
import useToast from "@/hooks/use-toast";
import { useRouter } from "next/navigation";
import { useState } from "react";
import TaskListsSection from "./task-lists-section";
Expand Down Expand Up @@ -38,9 +39,11 @@ const TeamBody = ({ taskLists, groupId }: TeamBodyProps) => {
(a, b) => a.displayIndex - b.displayIndex
);

const { mutate: postTaskList } = usePostTaskList();
const { mutate: patchTaskList } = usePatchTaskList(groupId);
const { mutate: postTaskList, isPending: isPostPending } = usePostTaskList();
const { mutate: patchTaskList, isPending: isPatchPending } =
usePatchTaskList(groupId);
const { mutate: deleteTaskList } = useDeleteTaskList(groupId);
const { success, error, warning } = useToast();

const [selectedTaskList, setSelectedTaskList] = useState<TaskList | null>(
null
Expand All @@ -65,17 +68,36 @@ const TeamBody = ({ taskLists, groupId }: TeamBodyProps) => {
} = usePrompt();

const handleAddTaskList = (name: string) => {
closeAddModal();
postTaskList({ groupId, name }, {});
postTaskList(
{ groupId, name },
{
onSuccess: () => {
success("할 일을 추가했습니다. ");
closeAddModal();
},
onError: (err: any) => {
const msg = err.response.data.message ?? "할 일 추가에 실패했습니다.";
error(msg);
},
}
);
};

const handlePatchTaskList = (newName: string) => {
if (!selectedTaskList) return;

closeChangeModal();
patchTaskList(
{ groupId, taskListId: selectedTaskList.id, name: newName },
{}
{
onSuccess: () => {
closeChangeModal();
},
onError: (err: any) => {
const msg =
err.response.data.message ?? "할 일 목록 수정에 실패했습니다.";
error(msg);
},
}
);
};

Expand All @@ -100,8 +122,12 @@ const TeamBody = ({ taskLists, groupId }: TeamBodyProps) => {
{ groupId, taskListId: selectedTaskList.id },
{
onSuccess: () => {
success("할 일을 삭제했습니다.");
closeDeleteModal();
},
onError: () => {
error("할 일 삭제에 실패했습니다");
},
}
);
};
Expand Down Expand Up @@ -140,14 +166,18 @@ const TeamBody = ({ taskLists, groupId }: TeamBodyProps) => {
</div>

<AddModal>
<AddTaskListModalUI handleClick={handleAddTaskList} />
<AddTaskListModalUI
handleClick={handleAddTaskList}
isPending={isPostPending}
/>
</AddModal>

<ChangeModal>
{selectedTaskList && (
<ChangeTaskListModalUI
taskTitle={selectedTaskList.name}
handleClick={handlePatchTaskList}
isPending={isPatchPending}
/>
)}
</ChangeModal>
Expand Down
28 changes: 11 additions & 17 deletions src/app/[groupId]/_components/team-page-client.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client";

import { TeamBannerAdmin, TeamBannerMember } from "@/components/index";
import { TeamBannerAdmin } from "@/components/index";
import BannerAdminSkeleton from "@/components/skeleton/team-skeleton/banner-admin-skeleton";
import TeamBodySkeleton from "@/components/skeleton/team-skeleton/team-body-skeleton";
import TeamMemberSectionSkeleton from "@/components/skeleton/team-skeleton/team-member-section-skeleton";
Expand All @@ -20,7 +20,7 @@ const TeamPageClient = ({ groupId }: TeamPageClientProps) => {
const { data: groupInfo, isPending } = useGetGroupInfo(groupId);
const isAdmin = isUserAdmin(userInfo, groupId);

if (isPending || !groupInfo) {
if (isPending || !groupInfo || !userInfo) {
return (
<div
className={cn(
Expand Down Expand Up @@ -55,21 +55,15 @@ const TeamPageClient = ({ groupId }: TeamPageClientProps) => {
)}
>
<section className="pc:flex pc:justify-center">
{isAdmin ? (
<TeamBannerAdmin
groupName={groupInfo.name}
tasksTodo={tasksTodo}
tasksDone={tasksDone}
members={groupInfo.members}
groupId={groupId}
/>
) : (
<TeamBannerMember
groupId={groupId}
groupName={groupInfo.name}
members={groupInfo.members}
/>
)}
<TeamBannerAdmin
groupName={groupInfo.name}
tasksTodo={tasksTodo}
tasksDone={tasksDone}
members={groupInfo.members}
groupId={groupId}
isAdmin={isAdmin}
myId={userInfo.id}
/>
</section>

<section className="pc:mx-auto pc:w-full pc:max-w-[1120px]">
Expand Down
32 changes: 24 additions & 8 deletions src/app/[groupId]/editteam/_components/edit-team.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
import {
Button,
Icon,
LoadingSpinner,
ProfileEdit,
TextInput,
LoadingSpinner,
} from "@/components";
import EditTeamSkeleton from "@/components/skeleton/editteam-skeleton/editteam-skeleton";
import useGetGroupInfo from "@/hooks/api/group/use-get-group-info";
import usePatchGroup from "@/hooks/api/group/use-patch-group";
import { useImageUpload } from "@/hooks/image-upload/use-image-upload";
import useToast from "@/hooks/use-toast";
import cn from "@/utils/clsx";
import { useEffect, useRef, useState } from "react";

Expand All @@ -19,8 +21,9 @@ interface EditTeamProps {

const EditTeam = ({ groupId }: EditTeamProps) => {
const fileInputRef = useRef<HTMLInputElement>(null);
const { data: groupInfo } = useGetGroupInfo(groupId);

const { data: groupInfo, isPending: isGroupDataPending } =
useGetGroupInfo(groupId);
const { success, error, warning } = useToast();
const [groupName, setGroupName] = useState("");
const [initialImage, setInitialImage] = useState<string | null>();

Expand Down Expand Up @@ -60,19 +63,32 @@ const EditTeam = ({ groupId }: EditTeamProps) => {
};

const onSubmit = () => {
patchGroup({
name: groupName,
image: previews[0]?.url ?? initialImage ?? null,
});
patchGroup(
{
name: groupName,
image: previews[0]?.url ?? initialImage ?? null,
},
{
onSuccess: () => {
success("팀 정보를 수정했습니다.");
},
onError: () => {
error("팀 정보 수정을 실패했습니다.");
},
}
);
};
if (!groupInfo) return null;

const handleRemoveImage = () => {
if (previews[0]) {
removeImage(previews[0].id);
}
setInitialImage(null);
};

if (isGroupDataPending || !groupInfo) {
return <EditTeamSkeleton />;
}
return (
<main className="h-screen w-full flex-center">
<div
Expand Down
Original file line number Diff line number Diff line change
@@ -1,33 +1,37 @@
import { Reply, CommentListSkeleton } from "@/components";
import useGetComments from "@/hooks/api/comments/use-get-comments";
import usePatchTaskComment from "@/hooks/api/task/use-patch-task-comment";
import useDeleteTaskComment from "@/hooks/api/task/use-delete-task-comment";

interface TaskDetailCommentProps {
taskId: number;
}

const TaskDetailComment = ({ taskId }: TaskDetailCommentProps) => {
const { data: comments, isPending } = useGetComments(Number(taskId));
const { mutate: patchTaskComment } = usePatchTaskComment();
const { mutate: patchComment } = usePatchTaskComment();
const { mutate: deleteComment } = useDeleteTaskComment();

if (isPending || !comments) return <CommentListSkeleton />;

return (
<div>
<ul className="flex flex-col gap-4">
{comments.map((comment, idx) => {
return (
<li key={comment.id} className="flex flex-col gap-4">
{idx !== 0 && idx < comments.length && <hr />}
<Reply
comment={{
...comment,
writer: comment.user,
}}
/>
</li>
);
})}
{comments.map((comment, idx) => (
<li key={comment.id} className="flex flex-col gap-4">
{idx !== 0 && idx < comments.length && <hr />}
<Reply
comment={{
...comment,
writer: comment.user,
}}
onEdit={(commentId, content) =>
patchComment({ taskId, commentId, content })
}
onDelete={(commentId) => deleteComment({ taskId, commentId })}
/>
</li>
))}
</ul>
</div>
);
Expand Down
29 changes: 27 additions & 2 deletions src/app/[groupId]/tasklist/_components/task-list-container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ import {
import usePostTaskList from "@/hooks/api/task/use-post-task-list";
import usePrompt from "@/hooks/use-prompt";
import { countDoneTask } from "@/utils/util";
import { useRouter } from "next/navigation";
import { usePathname, useRouter } from "next/navigation";
import { useEffect, useState } from "react";
import Skeleton from "react-loading-skeleton";
import Link from "next/link";

interface TodoContainerProps {
groupId: number;
Expand All @@ -27,6 +29,7 @@ const TaskListContainer = ({
taskList,
isPending,
}: TodoContainerProps) => {
const pathName = usePathname();
const { mutate: createTaskList, isPending: isPostPending } =
usePostTaskList();
const { Modal: AddTaskListModal, openPrompt, closePrompt } = usePrompt(true);
Expand All @@ -36,6 +39,12 @@ const TaskListContainer = ({
createTaskList({ groupId: groupId, name: name });
};

const [optimisticTaskListId, setOptimisticTaskListId] = useState(taskListId);

useEffect(() => {
setOptimisticTaskListId(taskListId);
}, [taskListId]);

return (
<div
className={cn(
Expand Down Expand Up @@ -89,7 +98,22 @@ const TaskListContainer = ({
{!isPending ? (
taskList.map((task) => {
return (
<li key={task.id}>
<li
key={task.id}
className={cn(
"relative",
task.id === optimisticTaskListId
? "text-blue-200"
: "text-blue-700"
)}
onClick={() => setOptimisticTaskListId(task.id)}
>
<Link
href={`${pathName}?list=${task.id}`}
scroll={false}
className="absolute inset-0 z-0"
/>

<TaskCard
groupId={groupId}
taskListId={task.id}
Expand All @@ -107,6 +131,7 @@ const TaskListContainer = ({
height={54}
width={270}
containerClassName="flex-1"
borderRadius={12}
/>
)}
</ul>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { usePostArticleComment } from "@/hooks/api/articles/use-post-article-com
import { useGetUserInfoQuery } from "@/hooks/api/user/use-get-user-info-query";
import useGetArticleComments from "@/hooks/api/articles/use-get-article-comments";
import useToggleArticleLike from "@/hooks/api/articles/use-toggle-article-like";
import usePatchArticleComment from "@/hooks/api/articles/use-patch-article-comment";
import useDeleteArticleComment from "@/hooks/api/articles/use-delete-article-comment";
import LikeButton from "@/components/lottie/LikeButton";
import DefaultProfile from "@/assets/icons/ic-user.svg";

Expand All @@ -18,6 +20,8 @@ interface ArticleCommentsProps {

const ArticleComments = ({ article }: ArticleCommentsProps) => {
const { mutate, isPending } = usePostArticleComment();
const { mutate: patchComment } = usePatchArticleComment();
const { mutate: deleteComment } = useDeleteArticleComment();

const { data, fetchNextPage, hasNextPage, isFetchingNextPage } =
useGetArticleComments({ articleId: article.id });
Expand Down Expand Up @@ -129,7 +133,15 @@ const ArticleComments = ({ article }: ArticleCommentsProps) => {
{allComments.map((comment) => (
<div key={comment.id}>
<hr className="border-gray-300 pb-5" />
<Reply comment={comment} articleId={article.id} />
<Reply
comment={comment}
onEdit={(commentId, content) =>
patchComment({ commentId, content })
}
onDelete={(commentId) =>
deleteComment({ commentId, articleId: article.id })
}
/>
</div>
))}
<div ref={observerTarget} className="h-4" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
"use client";

import Link from "next/link";
import Image from "next/image";
import { Button } from "@/components/index";
import { Article } from "@/types/article";

interface ArticleContentsProps {
Expand All @@ -19,7 +17,6 @@ const ArticleContents = ({ article }: ArticleContentsProps) => {
width={140}
height={140}
className="rounded-lg tablet:h-[200px] tablet:w-[200px]"
onError={() => console.log("이미지 로드 실패:", article.image)}
/>
)}
<p className="whitespace-pre-wrap break-words">{article.content}</p>
Expand Down
Loading
Loading