Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
24 changes: 14 additions & 10 deletions src/features/projects/api/projectsApi.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import {
addDoc,
arrayRemove,
arrayUnion,
collection,
doc,
serverTimestamp,
deleteDoc,
updateDoc,
arrayUnion,
arrayRemove,
} from "firebase/firestore";

import type { ApiResMessage } from "@entities/projects/types/firebase";

import { db } from "@shared/firebase/firebase";
import type { ProjectItemInsertReq } from "@shared/types/project";
import {
RecruitmentStatus,
type ProjectItemInsertReq,
} from "@shared/types/project";

/** firebase projects에 item 등록 */
export const insertProjectItem = async (
Expand All @@ -39,25 +41,27 @@ export const insertProjectItem = async (
}
};

/** firebase projectsItem 삭제 */
export const deleteProjectItem = async (id: string): Promise<ApiResMessage> => {
if (!window.confirm("정말로 삭제하시겠습니까?")) {
/** project 모집 마감 */
export const doneProjectItem = async (id: string): Promise<ApiResMessage> => {
if (!window.confirm("이대로 프로젝트를 모집을 마감 하시겠습니까?")) {
return { success: false, message: "" };
}

try {
const docRef = doc(db, "projects", id);
await deleteDoc(docRef);
await updateDoc(docRef, {
status: RecruitmentStatus.completed,
});

return {
success: true,
message: "프로젝트를 정상적으로 삭제하였습니다.",
message: "프로젝트가 정상적으로 마감 되었습니다.",
};
} catch (err) {
console.log(err);
return {
success: false,
message: "프로젝트 삭제에 실패하였습니다.",
message: "프로젝트가 마감되지 않았습니다.",
};
}
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,45 +1,42 @@
import { useMutation, type UseMutationResult } from "@tanstack/react-query";
import { useNavigate } from "react-router-dom";

import { deleteProjectItem } from "@features/projects/api/projectsApi";
import { doneProjectItem } from "@features/projects/api/projectsApi";

import type { ApiResMessage } from "@entities/projects/types/firebase";

import queryClient from "@shared/react-query/queryClient";
import { useAuthStore } from "@shared/stores/authStore";

interface IDsType {
postID: string;
projectID: string;
projectOwnerID: string;
}

const useProjectDelete = (): UseMutationResult<
ApiResMessage,
Error,
IDsType
> => {
const Navigate = useNavigate();
const useProjectDone = (): UseMutationResult<ApiResMessage, Error, IDsType> => {
const user = useAuthStore((state) => state.user);

return useMutation({
mutationFn: ({ postID, projectOwnerID }: IDsType) => {
mutationFn: ({ projectID, projectOwnerID }: IDsType) => {
if (user?.uid !== projectOwnerID) {
throw new Error("삭제 권한이 없습니다.");
}
return deleteProjectItem(postID);
return doneProjectItem(projectID);
},
onSuccess: (data) => {
onSuccess: (data, { projectID }) => {
if (data.message) {
alert(data.message);
}
// 게시글 삭제 후 목록페이지로 이동
if (data.success) {
Navigate("/project");
queryClient.invalidateQueries({
queryKey: ["project-detail", projectID],
});
return;
}
},
onError: (err) => {
alert(err || "정상적으로 삭제되지 않았습니다.");
alert(err || "정상적으로 마감되지 않았습니다.");
console.log(err);
},
});
};
export default useProjectDelete;
export default useProjectDone;
65 changes: 50 additions & 15 deletions src/features/projects/ui/ProjectDelete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,79 @@ import { Box, styled, Typography } from "@mui/material";
import type { JSX } from "react";
import { useParams } from "react-router-dom";

import useProjectDelete from "@features/projects/queries/useProjectDelete";
import useProjectDelete from "@features/projects/queries/useProjectDone";

const ProjectDelete = ({
export const ProjectDone = (): JSX.Element => {
return (
<MessageBtn className="gray">
<Typography fontWeight={600}>모집 마감</Typography>
</MessageBtn>
);
};

export const ProjectDones = ({
projectOwnerID,
}: {
projectOwnerID: string;
}): JSX.Element => {
const { id: postID } = useParams();
const { id: projectID } = useParams();
const { mutate: projectdelete, isPending } = useProjectDelete();

const handleDeleteBtn = (): void => {
if (postID && !isPending) {
projectdelete({ postID, projectOwnerID });
const handleIsDone = (): void => {
if (projectID && !isPending) {
projectdelete({ projectID, projectOwnerID });
}
};

const handleModify = (): void => {
// Navigate '/project/insert로 이동'
// state로 폼 넘김
// 이푸 state 존재 여부에 따라 등록, 수정 나눌 예정
// form을 나눈다면 여기서 나눠서 보낼 수 있도록 ...
alert("아직없어염..");
};

return (
<MessageBtn onClick={handleDeleteBtn}>
<Typography>프로젝트 삭제</Typography>
</MessageBtn>
<Box display={"flex"} gap={1}>
<MessageBtn className="white" onClick={handleModify}>
<Typography>수정하기</Typography>
</MessageBtn>

<MessageBtn className="red" onClick={handleIsDone}>
<Typography>모집 마감 하기</Typography>
</MessageBtn>
</Box>
);
};

export default ProjectDelete;

const MessageBtn = styled(Box)`
flex: 1;
display: flex;
align-items: center;
justify-content: center;
height: 4rem;
border-radius: 4px;
color: white;
background-color: tomato;
transition: background-color 0.3s ease;
cursor: pointer;

&:hover {
background-color: #e14b30;
&.white {
border: 1px solid #dddddd;
&:hover {
background-color: #f4f4f4;
}
}

&.red {
color: white;
background-color: tomato;
&:hover {
background-color: #e14b30;
}
}

&.gray {
color: #303030;
background-color: #f0f0f0;
cursor: default;
}
`;
7 changes: 4 additions & 3 deletions src/features/projects/ui/ProjectLike.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,14 @@ const StatusBox = styled("div")`
font-size: 12px;
font-weight: 600;
letter-spacing: 0.025em;
color: white;
border-radius: 50px;
border-radius: 4px;

&.ing {
color: white;
background-color: black;
}
&.done {
background-color: ${({ theme }) => theme.palette.primary.main};
color: #303030;
background-color: #f0f0f0;
}
`;
13 changes: 6 additions & 7 deletions src/pages/project-detail/ui/ProjectDetailPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ import { type JSX } from "react";
import { useNavigate, useParams } from "react-router-dom";

import ProjectApplyForm from "@features/projects/ui/ProjectApplyForm";
import ProjectDelete from "@features/projects/ui/ProjectDelete";
import { ProjectDone, ProjectDones } from "@features/projects/ui/ProjectDelete";
import ProjectLike from "@features/projects/ui/ProjectLike";
import ProjectModify from "@features/projects/ui/ProjectModify";

import useProjectsItem from "@entities/projects/queries/useProjectsItem";
import ProjectApply from "@entities/projects/ui/post-info/ProjectApply";
Expand Down Expand Up @@ -123,11 +122,11 @@ const ProjectDetailPage = (): JSX.Element | null => {
</CardBox>
<CardBox>
<ProjectApply applicants={project.applicants.length} />
{user?.uid !== project.projectOwner.id ? (
<Box display={"flex"} gap={1}>
<ProjectModify />
<ProjectDelete projectOwnerID={project?.projectOwner.id} />
</Box>

{project.status === "모집완료" ? (
<ProjectDone />
) : user?.uid === project.projectOwner.id ? (
<ProjectDones projectOwnerID={project?.projectOwner.id} />
) : (
<ProjectApplyForm applicants={project?.applicants || []} />
)}
Expand Down