From ea9dfefccff7184dca4fbba68ba442345a6bb603 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=EB=8B=A4=EB=B9=88?= <116141225+czmcm5@users.noreply.github.com> Date: Fri, 27 Jun 2025 16:14:22 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20users=EC=97=90=20=EB=82=B4=EA=B0=80=20?= =?UTF-8?q?=EB=93=B1=EB=A1=9D=ED=95=9C=20=ED=94=84=EB=A1=9C=EC=A0=9D?= =?UTF-8?q?=ED=8A=B8=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/projects/api/userAPi.ts | 33 +++++++++++++ .../projects/hook/useProjectInsertForm.ts | 48 ++++++++++--------- .../projects/queries/useProjectInsert.ts | 13 +++-- src/shared/api/userApi.ts | 18 +++++++ src/shared/queries/useUserProfile.ts | 12 +++++ src/shared/types/user.ts | 1 + 6 files changed, 99 insertions(+), 26 deletions(-) create mode 100644 src/features/projects/api/userAPi.ts create mode 100644 src/shared/api/userApi.ts create mode 100644 src/shared/queries/useUserProfile.ts diff --git a/src/features/projects/api/userAPi.ts b/src/features/projects/api/userAPi.ts new file mode 100644 index 0000000..580758b --- /dev/null +++ b/src/features/projects/api/userAPi.ts @@ -0,0 +1,33 @@ +import { arrayUnion, doc, updateDoc } from "firebase/firestore"; + +import type { ApiResMessage } from "@entities/projects/types/firebase"; + +import { db } from "@shared/firebase/firebase"; + +/** + * 내가 등록한 프로젝트 등록 + * users - myProjects에 ProjectID 넣기 + * */ +export const updateUserMyProject = async ( + uid: string, + projectID: string +): Promise => { + const usersRef = doc(db, "users", uid); + + try { + await updateDoc(usersRef, { + myProjects에: arrayUnion(projectID), + }); + + return { + success: true, + message: "", + }; + } catch (err) { + console.log(err); + return { + success: false, + message: "profile update실패. 동작이 반복 될 시 관리자에게 문의 주세요.", + }; + } +}; diff --git a/src/features/projects/hook/useProjectInsertForm.ts b/src/features/projects/hook/useProjectInsertForm.ts index f647060..2c7a37f 100644 --- a/src/features/projects/hook/useProjectInsertForm.ts +++ b/src/features/projects/hook/useProjectInsertForm.ts @@ -3,6 +3,8 @@ import { useState } from "react"; import useProjectInsert from "@features/projects/queries/useProjectInsert"; +import { useUserProfile } from "@shared/queries/useUserProfile"; +import { useAuthStore } from "@shared/stores/authStore"; import { ProjectCategory, RecruitmentStatus, @@ -10,7 +12,7 @@ import { type ProjectItemInsertReq, } from "@shared/types/project"; import { ExpectedPeriod } from "@shared/types/schedule"; -import { UserExperience } from "@shared/types/user"; +import { type User } from "@shared/types/user"; // 이하 InitData 개선 예정 type Setp1Type = Pick< @@ -41,18 +43,14 @@ interface InsertFormResult { } const useProjectInsertForm = (): InsertFormResult => { - const { mutate: insertItem, isPending } = useProjectInsert(); + const user = useAuthStore((state) => state.user); + const { data: userProfile } = useUserProfile(user?.uid || ""); + const { mutate: insertProject, isPending } = useProjectInsert(); const [currentStep, setCurrentStep] = useState(1); - // Step1 상태 // const [formStep1, setFormStep1] = useState(initForm1); - // Step2 상태 - const [formStep2, setFormStep2] = useState({ - teamSize: 0, - expectedPeriod: "", - techStack: [], - positions: [], - }); + const [formStep2, setFormStep2] = useState(initForm2); + const handleChangeStep2 = (field: keyof Step2Type, value: any): void => { setFormStep2((prev) => ({ ...prev, [field]: value })); }; @@ -67,15 +65,19 @@ const useProjectInsertForm = (): InsertFormResult => { }; const submit = async (): Promise => { + if (!userProfile) return; if (!window.confirm("등록을 완료 하시겠습니까?")) return; if (isPending) return; + + // lint에러를 피하기 위한... + // 추후에 step3, step4 훅 만들 때 가져다 쓰시라고 미리 만들어놨습니다! + console.log(initForm2, initForm3, initForm4); + // form 검사 추가 바람 - insertItem(TestData); - }; - // lint에러를 피하기 위한... - // 추후에 step3, step4 훅 만들 때 가져다 쓰시라고 미리 만들어놨습니다! - console.log(initForm2, initForm3, initForm4); + // projects에 insert + insertProject(TestData(userProfile)); + }; return { form: { @@ -120,14 +122,14 @@ const initForm4 = { }; // 테스트용 form 입니다. -const TestData: ProjectItemInsertReq = { +const TestData = (user: User): ProjectItemInsertReq => ({ projectOwner: { - id: "user1234", - name: "홍길동", - userRole: "frontend", - email: "test@test.com", - experience: UserExperience.junior, - avatar: "https://via.placeholder.com/150", + id: user.id, + name: user.name, + userRole: user.userRole, + email: user.email, + experience: user.experience, + avatar: user.avatar, }, applicants: [], status: RecruitmentStatus.recruiting, @@ -180,4 +182,4 @@ const TestData: ProjectItemInsertReq = { likedUsers: [], category: ProjectCategory.webDevelopment, closedDate: Timestamp.now(), -}; +}); diff --git a/src/features/projects/queries/useProjectInsert.ts b/src/features/projects/queries/useProjectInsert.ts index 75091c7..f9f3002 100644 --- a/src/features/projects/queries/useProjectInsert.ts +++ b/src/features/projects/queries/useProjectInsert.ts @@ -2,6 +2,7 @@ import { useMutation, type UseMutationResult } from "@tanstack/react-query"; import { useNavigate } from "react-router-dom"; import { insertProjectItem } from "@features/projects/api/projectsApi"; +import { updateUserMyProject } from "@features/projects/api/userAPi"; import type { ApiResMessage } from "@entities/projects/types/firebase"; @@ -23,11 +24,17 @@ const useProjectInsert = (): UseMutationResult< } return insertProjectItem(projectItem); }, - onSuccess: (data) => { + onSuccess: async (data) => { // 게시글 등록 후 본인 게시글로 이동 if (data.success && data.id) { - alert("게시글이 등록 되었습니다."); - Navigate(`/project/${data.id}`); + try { + await updateUserMyProject(user?.uid || "", data.id); + + alert("게시글이 등록 되었습니다."); + Navigate(`/project/${data.id}`); + } catch (err) { + console.log("users 업데이트 실패: ", err); + } } }, onError: (err) => { diff --git a/src/shared/api/userApi.ts b/src/shared/api/userApi.ts new file mode 100644 index 0000000..0538fe0 --- /dev/null +++ b/src/shared/api/userApi.ts @@ -0,0 +1,18 @@ +import { doc, setDoc, getDoc } from "firebase/firestore"; + +import { db } from "@shared/firebase/firebase"; +import type { User } from "@shared/types/user"; + +export const saveUser = async (uid: string, userInfo: User): Promise => { + const userDoc = doc(db, "users", uid); + await setDoc(userDoc, userInfo); +}; + +export const getUser = async (uid: string): Promise => { + const userDoc = doc(db, "users", uid); + const userSnap = await getDoc(userDoc); + if (userSnap.exists()) { + return userSnap.data() as User; + } + return null; +}; diff --git a/src/shared/queries/useUserProfile.ts b/src/shared/queries/useUserProfile.ts new file mode 100644 index 0000000..10d732b --- /dev/null +++ b/src/shared/queries/useUserProfile.ts @@ -0,0 +1,12 @@ +import { useQuery, type UseQueryResult } from "@tanstack/react-query"; + +import { getUser } from "@shared/api/userApi"; +import type { User } from "@shared/types/user"; + +export function useUserProfile(uid: string): UseQueryResult { + return useQuery({ + queryKey: ["userProfile", uid], + queryFn: () => getUser(uid), + enabled: !!uid, // uid가 있을 때만 쿼리 실행 + }); +} diff --git a/src/shared/types/user.ts b/src/shared/types/user.ts index ed25e75..0d24b64 100644 --- a/src/shared/types/user.ts +++ b/src/shared/types/user.ts @@ -8,6 +8,7 @@ export interface User { likeProjects?: string[]; // 좋아요 누른 프로젝트 appliedProjects?: string[]; // 지원한 프로젝트 introduceMyself?: string; // 자기소개 + myProjects?: string[]; // 내가 등록한 프로젝트 } export type UserRole = "frontend" | "backend" | "fullstack" | "designer" | "pm";