diff --git a/src/app/feedback/feedback.js b/src/app/feedback/feedback.js index a39a508..f902599 100644 --- a/src/app/feedback/feedback.js +++ b/src/app/feedback/feedback.js @@ -1,215 +1,105 @@ "use client"; -import { useState } from "react"; +import { useState, useEffect } from "react"; import * as PR from './feedback_s'; import { ContentContainer, Space } from '@/components/common_s'; +import axiosWithAuthorization from "@/context/axiosWithAuthorization"; +import { useAlert } from "@/context/AlertContext"; +export default function PeerReview({ projectId, sprintId }) { + const { showAlert } = useAlert(); -const feedbackData = { - 1: { - "success": true, - "status": 200, - "data": { - "content": [ - { - "feedbackId": 3, - "message": "현태님, 이번 프로젝트 동안 커뮤니케이션 부분에서 조금 아쉬운 점이 있었습니다. 중요한 회의에 참석하지 못한 경우가 있었고, 공유된 정보를 확인하는 데에 조금 더 주의를 기울인다면 작업이 더욱 원활하게 진행될 수 있을 것입니다. 맡은 역할을 좀 더 충실히 수행하면 전체 팀의 부담을 줄이는 데 큰 도움이 될 것입니다. 다음 프로젝트에서는 더욱 적극적으로 협업하며 소통을 강화해 주시면 좋겠습니다. 함께 일하는 데 아주 긍정적인 영향을 미칠 것이라 믿습니다!", - "receivedDt": "2025-03-17" - }, - { - "feedbackId": 2, - "message": "이번 프로젝트에서 협업 방식이 좋았습니다!", - "receivedDt": "2025-03-17" - }, - { - "feedbackId": 4, - "message": "현태님, 이번 프로젝트 동안 커뮤니케이션 부분에서 조금 아쉬운 점이 있었습니다. 중요한 회의에 참석하지 못한 경우가 있었고, 공유된 정보를 확인하는 데에 조금 더 주의를 기울인다면 작업이 더욱 원활하게 진행될 수 있을 것입니다. 맡은 역할을 좀 더 충실히 수행하면 전체 팀의 부담을 줄이는 데 큰 도움이 될 것입니다. 다음 프로젝트에서는 더욱 적극적으로 협업하며 소통을 강화해 주시면 좋겠습니다. 함께 일하는 데 아주 긍정적인 영향을 미칠 것이라 믿습니다!", - "receivedDt": "2025-03-17" - }, - { - "feedbackId": 5, - "message": "이번 프로젝트에서 협업 방식이 좋았습니다!", - "receivedDt": "2025-03-17" - } - ], - "pageable": { - "pageNumber": 0, - "pageSize": 2, - "sort": [], - "offset": 0, - "paged": true, - "unpaged": false - }, - "first": true, - "last": false, - "size": 2, - "number": 0, - "sort": [], - "numberOfElements": 2, - "empty": false - }, - "timestamp": "2025-03-17T21:32:43.731566" - }, - 2: { - "success": true, - "status": 200, - "data": { - "content": [ - { - "feedbackId": 3, - "message": "현태님, 이번 프로젝트 동안 커뮤니케이션 부분에서 조금 아쉬운 점이 있었습니다. 중요한 회의에 참석하지 못한 경우가 있었고, 공유된 정보를 확인하는 데에 조금 더 주의를 기울인다면 작업이 더욱 원활하게 진행될 수 있을 것입니다. 맡은 역할을 좀 더 충실히 수행하면 전체 팀의 부담을 줄이는 데 큰 도움이 될 것입니다. 다음 프로젝트에서는 더욱 적극적으로 협업하며 소통을 강화해 주시면 좋겠습니다. 함께 일하는 데 아주 긍정적인 영향을 미칠 것이라 믿습니다!", - "receivedDt": "2025-03-17" - }, - { - "feedbackId": 2, - "message": "이번 프로젝트에서 협업 방식이 좋았습니다!", - "receivedDt": "2025-03-17" - } - ], - "pageable": { - "pageNumber": 0, - "pageSize": 2, - "sort": [], - "offset": 0, - "paged": true, - "unpaged": false - }, - "first": true, - "last": false, - "size": 2, - "number": 0, - "sort": [], - "numberOfElements": 2, - "empty": false - }, - "timestamp": "2025-03-17T21:32:43.731566" - }, - 3: { - "success": true, - "status": 200, - "data": { - "content": [ - { - "feedbackId": 3, - "message": "현태님, 이번 프로젝트 동안 커뮤니케이션 부분에서 조금 아쉬운 점이 있었습니다. 중요한 회의에 참석하지 못한 경우가 있었고, 공유된 정보를 확인하는 데에 조금 더 주의를 기울인다면 작업이 더욱 원활하게 진행될 수 있을 것입니다. 맡은 역할을 좀 더 충실히 수행하면 전체 팀의 부담을 줄이는 데 큰 도움이 될 것입니다. 다음 프로젝트에서는 더욱 적극적으로 협업하며 소통을 강화해 주시면 좋겠습니다. 함께 일하는 데 아주 긍정적인 영향을 미칠 것이라 믿습니다!", - "receivedDt": "2025-03-17" - }, - { - "feedbackId": 2, - "message": "이번 프로젝트에서 협업 방식이 좋았습니다!", - "receivedDt": "2025-03-17" - } - ], - "pageable": { - "pageNumber": 0, - "pageSize": 2, - "sort": [], - "offset": 0, - "paged": true, - "unpaged": false - }, - "first": false, - "last": true, - "size": 2, - "number": 0, - "sort": [], - "numberOfElements": 2, - "empty": false - }, - "timestamp": "2025-03-17T21:32:43.731566" - }, -} - -export default function PeerReview() { - // <----------------------------------API 연결시 필요하면 수정 --------------------------------------> - // <--------------------------------------------여기 아래부터 시작------------------------------------> - const [openFeedback, setOpenFeedback] = useState({}); - - const toggleFeedback = (sprintNum) => { - setOpenFeedback(prev => ({ - ...prev, - [sprintNum]: !prev[sprintNum] - })); - }; - // <----------------------------------API 연결시 필요하면 수정 --------------------------------------> - // <--------------------------------------------여기 위까지 끝--------------------------------------> + // 피드백 관련 상태 + const [feedbackList, setFeedbackList] = useState([]); + const [lastFeedbackId, setLastFeedbackId] = useState(null); + const [hasMoreFeedback, setHasMoreFeedback] = useState(true); + const [isFetchingFeedback, setIsFetchingFeedback] = useState(false); - return ( - - - 동료평가 + // 피드백 조회 함수 (페이지네이션 적용; 예: size=5) + const fetchFeedback = async () => { + if (isFetchingFeedback || !hasMoreFeedback) return; // 이미 요청 중이거나 더 불러올 데이터 없음 + setIsFetchingFeedback(true); + try { + const res = await axiosWithAuthorization.get(`/feedbacks/${projectId}`, { + params: { + sprintId: sprintId, + lastFeedbackId: lastFeedbackId, // 첫 페이지일 경우 null + size: 5, + }, + }); + console.log("피드백 응답:", res.data); + // 응답 구조: { data: { content: [...], last: true/false, ... }, ... } + const newFeedback = res.data.data.content || []; + const isLastPage = res.data.data.last; - {/* <----------------------------------API 연결시 필요하면 수정 --------------------------------------> - <--------------------------------------map 함수 부분--------------------------------------> */} - {Object.entries(feedbackData).map(([sprintNum, sprintData]) => { - const feedbackList = sprintData.data.content; + if (newFeedback.length === 0) { + setHasMoreFeedback(false); + } else { + setFeedbackList((prev) => [...prev, ...newFeedback]); + const nextLastId = newFeedback[newFeedback.length - 1].feedbackId; + setLastFeedbackId(nextLastId); + } + if (isLastPage) { + setHasMoreFeedback(false); + } + } catch (error) { + showAlert("error", error.response?.data?.message || "피드백 조회 실패"); + console.log(error.response?.data); + } finally { + setIsFetchingFeedback(false); + } + }; - return ( -
- toggleFeedback(sprintNum)}> - {openFeedback[sprintNum] ? "▼" : "▶"} - Sprint {sprintNum} - + // 스프린트가 변경되면 피드백 목록 상태 초기화 후 새로 조회 + useEffect(() => { + setFeedbackList([]); + setLastFeedbackId(null); + setHasMoreFeedback(true); + fetchFeedback(); + }, [sprintId]); - {openFeedback[sprintNum] && ( - - - - - # - - - 날짜 - - - 내용 - - - - - {/* <----------------------------------API 연결시 필요하면 수정 --------------------------------------> - <--------------------------------------map 함수 부분--------------------------------------> */} - {feedbackList.map((feedback, index) => ( - - - {index + 1} - - - {feedback.receivedDt} - - - {feedback.message} - - - ))} - - - )} -
- ); - })} -
- -
- ) -} \ No newline at end of file + return ( + + + 동료평가 + {/* 스프린트 제목 및 피드백 목록 */} + + Sprint {sprintId} + + + + + # + + 날짜 + + 내용 + + + + {feedbackList.map((feedback, index) => ( + + + {index + 1} + + + {feedback.receivedDt} + + + {feedback.message} + + + ))} + + + {/* 추가 피드백이 있으면 "더보기" 버튼 */} + {hasMoreFeedback && ( + + )} + + + + ); +} diff --git a/src/app/message/message.js b/src/app/message/message.js index 4eefb23..8926c40 100644 --- a/src/app/message/message.js +++ b/src/app/message/message.js @@ -1,64 +1,121 @@ "use client"; -import { useSearchParams } from "next/navigation"; import { useState } from "react"; -import { useRouter } from "next/navigation"; -import * as MS from './message_s'; -import { ContentContainer, Space } from '@/components/common_s'; +import { useSearchParams, useRouter } from "next/navigation"; +import * as MS from "./message_s"; +import { ContentContainer, Space } from "@/components/common_s"; import Image from "next/image"; +import axiosWithAuthorization from "@/context/axiosWithAuthorization"; +import { useAlert } from "@/context/AlertContext"; -export default function Message({ }) { - const [message, setMessage] = useState(""); - const [gptMessage, setGptMessage] = useState("현태님, 이번 프로젝트 동안 커뮤니케이션 부분에서 조금 아쉬운 점이 있었습니다. 중요한 회의에 참석하지 못한 경우가 있었고, 공유된 정보를 확인하는 데에 조금 더 주의를 기울인다면 작업이 더욱 원활하게 진행될 수 있을 것입니다. 맡은 역할을 좀 더 충실히 수행하면 전체 팀의 부담을 줄이는 데 큰 도움이 될 것입니다. 다음 프로젝트에서는 더욱 적극적으로 협업하며 소통을 강화해 주시면 좋겠습니다. 함께 일하는 데 아주 긍정적인 영향을 미칠 것이라 믿습니다!"); - const router = useRouter(); +export default function Message({}) { + const [message, setMessage] = useState(""); + const [gptMessage, setGptMessage] = useState(""); + const [isLoadingRefinement, setIsLoadingRefinement] = useState(false); + const router = useRouter(); + const { showAlert } = useAlert(); - const searchParams = useSearchParams(); - const memberName = searchParams.get("name"); - const profileImage = searchParams.get("profileImage"); + const searchParams = useSearchParams(); + const memberName = searchParams.get("name"); + const profileImage = searchParams.get("profileImage"); + const sprintId = searchParams.get("sprintId"); + const receiverId = searchParams.get("receiverId"); - return ( - - - - - - - + const handleRefinement = async () => { + if (!message.trim()) { + showAlert("error", "먼저 메시지를 작성해주세요."); + return; + } + setIsLoadingRefinement(true); + try { + const res = await axiosWithAuthorization.post("/feedbacks/refinement", { + originalMessage: message, + }); - - {memberName}(님)에게 전할 메시지를 적어보세요! - setMessage(e.target.value)} - maxLength={300} - /> - 작성완료 - + const improvedMessage = res.data.data?.refinedMessage; + if (improvedMessage) { + console.log(improvedMessage) + setGptMessage(improvedMessage); + } else { + showAlert("error", "개선된 메시지를 받지 못했습니다."); + } + } catch (error) { + showAlert( + "error", + error.response?.data?.message || "피드백 개선 요청 실패" + ); + } finally { + setIsLoadingRefinement(false); + } + }; - - - GPT 생성 답변 - - setGptMessage(e.target.value)} - maxLength={600} - /> - - 수정하기 - 전송하기 - - - - - ) + // 개선된 메시지 전송(API: /feedbacks/sent) 요청 핸들러 + const handleSendFeedback = async () => { + if (!gptMessage.trim()) { + showAlert("error", "먼저 개선된 메시지를 작성해주세요."); + return; + } + try { + await axiosWithAuthorization.post("/feedbacks/sent", { + sprintId: Number(sprintId), + receiverId: Number(receiverId), + message: gptMessage, + }); + showAlert("success", "피드백 전송 완료"); + // 전송 후 이전 페이지로 이동하거나 원하는 동작을 수행 + router.back(); + } catch (error) { + showAlert( + "error", + error.response?.data?.message || "피드백 전송 실패" + ); + } + }; + return ( + + + + + + + + + + {memberName}(님)에게 전할 메시지를 적어보세요! + setMessage(e.target.value)} + maxLength={300} + /> + + {isLoadingRefinement ? "요청중..." : "작성완료"} + + + + {/* GPT의 응답이 있을 때만 GPTMessageBox를 렌더링 */} + {gptMessage && ( + + GPT 생성 답변 + setGptMessage(e.target.value)} + maxLength={600} + /> + + 수정하기 + + 전송하기 + + + + )} + + + + ); }