diff --git a/src/app/login/login.js b/src/app/login/login.js index 3b5a42d..cdf7787 100644 --- a/src/app/login/login.js +++ b/src/app/login/login.js @@ -20,7 +20,7 @@ export default function Login() { window.location.href = res.data.url; // OAuth 인증 페이지 redirect console.log(res.data) } catch (error) { - console.error("로그인 요청 실패:", error.response ? error.response.data : error.message); + console.log("로그인 요청 실패:", error.response ? error.response.data : error.message); } }; diff --git a/src/app/mypage/approve_modal.js b/src/app/mypage/approve_modal.js index 1c085f5..9c52b16 100644 --- a/src/app/mypage/approve_modal.js +++ b/src/app/mypage/approve_modal.js @@ -117,7 +117,7 @@ export default function ApproveModal({ isOpen, onClose, projectId }) { console.log("프로젝트 개별 정보 조회:", res.data); return res.data.data; } catch (error) { - showAlert("error", error.response.data.data.message); + showAlert("error", "프로젝트 정보를 불러올 수 없습니다."); console.log(error.response.data); } }; @@ -136,7 +136,7 @@ export default function ApproveModal({ isOpen, onClose, projectId }) { console.log("프로젝트 가입 신청 목록 조회:", res.data); return res.data.data.content || []; } catch (error) { - showAlert("error", error.response.data.data.message); + showAlert("error","가입 신청자가 없습니다."); console.log(error.response.data); return []; } diff --git a/src/app/mypage/mypage.js b/src/app/mypage/mypage.js index ceb2012..334ffcf 100644 --- a/src/app/mypage/mypage.js +++ b/src/app/mypage/mypage.js @@ -93,7 +93,7 @@ export default function My({ projectId }) { setSprintLast(response.last); } catch (error) { - console.error("스프린트 불러오기 실패:", error.message); + console.log("스프린트 불러오기 실패:", error.message); } }; @@ -135,7 +135,7 @@ export default function My({ projectId }) { setCurrentSprint(updatedSprints[currentSprintIndex]); } } catch (error) { - console.error("현재 스프린트 갱신 실패:", error.message); + console.log("현재 스프린트 갱신 실패:", error.message); } }; diff --git a/src/app/task/task.js b/src/app/task/task.js index 4d509d6..e95114d 100644 --- a/src/app/task/task.js +++ b/src/app/task/task.js @@ -68,7 +68,8 @@ export default function Task({ projectId }) { } } catch (error) { - console.error("태스크 로딩 실패:", error.message); + console.log("태스크 로딩 실패:", error.message); + showAlert("태스크를 불러올 수 없습니다.") setHasMore(false); } finally { setIsFetching(false); diff --git a/src/app/team/leave_modal.js b/src/app/team/leave_modal.js index 579a810..4f8d8e9 100644 --- a/src/app/team/leave_modal.js +++ b/src/app/team/leave_modal.js @@ -17,7 +17,7 @@ export default function LeaveModal({ selectedProject, onClose }) { showAlert("success", "프로젝트 나가기가 완료되었습니다."); onClose(); // 모달 닫기 후 추가 작업(예: 페이지 리디렉션) 필요 시 추가 } catch (error) { - console.error(error); + console.log(error); showAlert("error", error.response?.data?.message || "프로젝트 나가기 실패"); } }; diff --git a/src/app/team/project_modal.js b/src/app/team/project_modal.js index 6201b50..a55d43f 100644 --- a/src/app/team/project_modal.js +++ b/src/app/team/project_modal.js @@ -73,7 +73,8 @@ export default function ProjectModal({ onProjectCreated?.(); onClose(); // 모달 닫기 } catch (error) { - console.error(`${isEditing ? "프로젝트 수정 실패" : "프로젝트 생성 실패"}:`, error.message); + console.log(`${isEditing ? "프로젝트 수정 실패" : "프로젝트 생성 실패"}:`, error.message); + showAlert("success", `${isEditing ? "프로젝트 수정 실패" : "프로젝트 생성 실패"}:`); } }; diff --git a/src/app/team/section_s.js b/src/app/team/section_s.js index a74ca6c..1894327 100644 --- a/src/app/team/section_s.js +++ b/src/app/team/section_s.js @@ -225,25 +225,28 @@ export const ProjectHButton = styled.button` `; const StyledButton = styled.button` - font-size: 12px; - font-weight: bold; - color: white; - background: ${({ $disabled }) => - $disabled ? "#B3B3B3" : "#796AD9"}; - border: 2px solid ${({ $disabled }) => - $disabled ? "#B3B3B3" : "#796AD9"}; - border-radius: 12px; - padding: 6px 12px; - cursor: pointer; - min-width: 85px; - transition: 0.2s ease-in-out; - - &:hover { - background: ${({ $disabled }) => - $disabled ? "#B3B3B3" : "#5a46c6"}; - border: 2px solid ${({ $disabled }) => - $disabled ? "#B3B3B3" : "#5a46c6"}; - } + font-size: 12px; + font-weight: bold; + color: white; + + background: ${({ $disabled, $joinStatus }) => + $disabled || $joinStatus === "PENDING" ? "#B3B3B3" : "#796AD9"}; + + border: 2px solid ${({ $disabled, $joinStatus }) => + $disabled || $joinStatus === "PENDING" ? "#B3B3B3" : "#796AD9"}; + + border-radius: 12px; + padding: 6px 12px; + cursor: pointer; + min-width: 85px; + transition: 0.2s ease-in-out; + + &:hover { + background: ${({ $disabled, $joinStatus }) => + $disabled || $joinStatus === "PENDING" ? "#B3B3B3" : "#5a46c6"}; + border: 2px solid ${({ $disabled, $joinStatus }) => + $disabled || $joinStatus === "PENDING" ? "#B3B3B3" : "#5a46c6"}; + } `; export const DeleteProjectButton = styled(StyledButton)` @@ -264,10 +267,14 @@ export function LeaveProjectButton({ onClick }) { ); } -export function JoinProjectButton({ onClick, isPending }) { - return ( - - {isPending ? "승인대기" : "가입신청"} - - ); +export function JoinProjectButton({ onClick, isPending, joinStatus }) { + return ( + + {joinStatus === "PENDING" ? "승인대기" : "가입 신청"} + + ); } \ No newline at end of file diff --git a/src/app/team/team.js b/src/app/team/team.js index 5fe988a..d9e2e8d 100644 --- a/src/app/team/team.js +++ b/src/app/team/team.js @@ -30,6 +30,8 @@ import { useAlert } from "@/context/AlertContext"; import axiosWithAuthorization from "@/context/axiosWithAuthorization"; + + export default function Team({ teamId }) { const { showAlert } = useAlert(); @@ -76,6 +78,7 @@ export default function Team({ teamId }) { const [isMembersFetching, setIsMembersFetching] = useState(false); const TeamId = Number(teamId); + const normalizeJoinStatus = (status) => status ?? "NONE"; useEffect(() => { const getUserInfo = async () => { @@ -141,11 +144,21 @@ export default function Team({ teamId }) { //project 가입 신청 const requestProjectJoin = async (projectId) => { try { - const res = await axiosWithAuthorization.post(`/projects/${projectId}/registration`); - return res.data.data.teamName; + const res = await axiosWithAuthorization.post(`/projects/${projectId}/registration`); + return res.data; + } catch (error) { + throw error.response?.data || error; // 명시적으로 throw + } + }; + + const cancelProjectJoin = async (projectId) => { + try { + const res = await axiosWithAuthorization.delete( + `/projects/${projectId}/registration/cancel` + ); + return res.data; } catch (error) { - showAlert("error", error.response.data.data.message); - console.log(error.response.data); + showAlert("error", error.response.data.data.message||"잠시 뒤 다시 시도해주세요"); } }; @@ -234,19 +247,23 @@ export default function Team({ teamId }) { const newOtherProjects = []; content.forEach(project => { - //유저가 프로젝트에 참여 중 + const status = project.currentUserParticipation?.status ?? "NONE"; + const newProject = { + ...project, + + }; + if (project.isParticipant) { - //상태 INACTIVE -> others - if (project.currentUserParticipation && project.currentUserParticipation.status === "INACTIVE") { - newOtherProjects.push(project); - } else { - newMyProjects.push(project); - } + if (status === "INACTIVE") { + newOtherProjects.push(newProject); + } else { + newMyProjects.push(newProject); + } } else { - newOtherProjects.push(project); + newOtherProjects.push(newProject); } - }); - + }); + setMyProjects(prev => [...prev, ...newMyProjects]); setOtherProjects(prev => [...prev, ...newOtherProjects]); @@ -450,22 +467,61 @@ export default function Team({ teamId }) { }; // 타 프로젝트 가입 신청 <-> 승인 대기 - const handleClick = (projectId) => { + const handleClick = async (project) => { + const projectId = project.projectInfo.projectId; + const status = normalizeJoinStatus(project.joinStatus); + + if (pendingProjects[projectId]) return; + setPendingProjects((prev) => ({ ...prev, - [projectId]: !prev[projectId] + [projectId]: true, })); - + try { - requestProjectJoin(projectId); + let updatedJoinStatus; + + if (status === "PENDING") { + await cancelProjectJoin(projectId); + updatedJoinStatus = "NONE"; + showAlert("success", "가입 신청이 취소되었습니다."); + } else { + await requestProjectJoin(projectId); + updatedJoinStatus = "PENDING"; + showAlert("success", "가입 신청이 완료되었습니다."); + } + + console.log(`프로젝트 ${projectId}의 새로운 상태:`, updatedJoinStatus); + + // 상태 업데이트 + setOtherProjects((prev) => + prev.map((p) => { + if (p.projectInfo.projectId === projectId) { + return { + ...p, + joinStatus: updatedJoinStatus, + currentUserParticipation: { + ...(p.currentUserParticipation || {}), + status: updatedJoinStatus, + }, + }; + } + return p; + }) + ); } catch (error) { - // 실패 시 상태를 다시 되돌림 (rollback) + showAlert("error", error.message || "오류가 발생했습니다."); + } finally { setPendingProjects((prev) => ({ ...prev, - [projectId]: !prev[projectId] + [projectId]: false, })); } }; + + + + // 멤버 이름 3글자 이상이면 축약 표시 const reduceMemberName = (name) => { @@ -805,9 +861,11 @@ export default function Team({ teamId }) { 프로젝트 홈 handleClick(project.projectInfo.projectId)} + onClick={() => handleClick(project)} isPending={pendingProjects[project.projectInfo.projectId]} + joinStatus={normalizeJoinStatus(project.joinStatus ?? project.currentUserParticipation?.status)} /> + )) diff --git a/src/components/Navbar_b.js b/src/components/Navbar_b.js index 05d9268..d946eab 100644 --- a/src/components/Navbar_b.js +++ b/src/components/Navbar_b.js @@ -6,6 +6,7 @@ import Image from "next/image"; import { useRouter } from "next/navigation"; import { logout } from "@/app/api/logout/logout"; +import { useAlert } from "@/context/AlertContext"; const Navbar_ = () => { @@ -21,8 +22,8 @@ const Navbar_ = () => { localStorage.removeItem("storedUser"); router.push("/login"); } catch (error) { - console.error("로그아웃 실패:", error); - alert("로그아웃에 실패했습니다."); + console.log("로그아웃 실패:", error); + showAlert("error", "로그아웃에 실패했습니다."); } }; diff --git a/src/components/modals-sw/TeamCreateModal.js b/src/components/modals-sw/TeamCreateModal.js index cb0c9ee..2394954 100644 --- a/src/components/modals-sw/TeamCreateModal.js +++ b/src/components/modals-sw/TeamCreateModal.js @@ -2,6 +2,7 @@ import React, { useEffect, useState } from "react"; import axios from "axios"; import * as S from "./team_create_modal_styles"; +import { useAlert } from "@/context/AlertContext"; const TeamCreateModal = ({ isOpen, onClose, onTeamCreated }) => { const [teamName, setTeamName] = useState(""); @@ -61,10 +62,11 @@ const TeamCreateModal = ({ isOpen, onClose, onTeamCreated }) => { onClose(); onTeamCreated(); } catch (error) { - console.error( + console.log( "팀 생성 실패:", error.response ? error.response.data : error.message ); + showAlert("error", "팀 생성에 실패했습니다."); } };