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
42 changes: 30 additions & 12 deletions src/components/card/my-homework-status-card.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,40 @@
'use client';

import type { HomeworkDetailResponseDto } from '@/api/openapi/models';
import { useRouter, useSearchParams } from 'next/navigation';
import { useMemo } from 'react';

import Button from '@/components/ui/button';
import { useGetMission } from '@/hooks/queries/mission-api';
import { useUserStore } from '@/stores/useUserStore';
import SubmitHomeworkModal from '../modals/submit-homework-modal';

interface MyHomeworkStatusProps {
missionId: number;
myHomework?: HomeworkDetailResponseDto;
isMissionClosed?: boolean;
onSelectHomework: (homeworkId: number) => void;
onRefetch?: () => void;
}

export default function MyHomeworkStatusCard({
missionId,
myHomework,
isMissionClosed = false,
onSelectHomework,
onRefetch,
}: MyHomeworkStatusProps) {
const router = useRouter();
const searchParams = useSearchParams();
const memberId = useUserStore((state) => state.memberId);

const { data: mission } = useGetMission(missionId);

const myHomework = useMemo(() => {
if (!mission?.homeworks || !memberId) return null;

return mission.homeworks.find((hw) => hw.submitterId === memberId) ?? null;
}, [mission?.homeworks, memberId]);

const isMissionClosed = mission?.status === 'ENDED';

const handleSelectHomework = (homeworkId: number) => {
const params = new URLSearchParams(searchParams.toString());
params.set('homeworkId', String(homeworkId));
router.push(`?${params.toString()}`);
};

// 미제출 상태
if (!myHomework || myHomework.homeworkStatus === 'NOT_SUBMITTED') {
return (
Expand All @@ -30,7 +46,7 @@ export default function MyHomeworkStatusCard({
<span className="text-text-subtlest font-designer-14r">
아직 과제를 제출하지 않았습니다.
</span>
<SubmitHomeworkModal missionId={missionId} onSuccess={onRefetch} />
<SubmitHomeworkModal missionId={missionId} />
</div>
</div>
);
Expand All @@ -55,7 +71,8 @@ export default function MyHomeworkStatusCard({
color="outlined"
className="mt-100"
onClick={() =>
myHomework.homeworkId && onSelectHomework(myHomework.homeworkId)
myHomework.homeworkId &&
handleSelectHomework(myHomework.homeworkId)
}
>
과제 상세 보기
Expand Down Expand Up @@ -105,7 +122,8 @@ export default function MyHomeworkStatusCard({
<Button
color="outlined"
onClick={() =>
myHomework.homeworkId && onSelectHomework(myHomework.homeworkId)
myHomework.homeworkId &&
handleSelectHomework(myHomework.homeworkId)
}
>
과제 상세 보기
Expand Down
91 changes: 8 additions & 83 deletions src/components/contents/homework-detail-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@
import { useRouter, useSearchParams } from 'next/navigation';
import { useState } from 'react';

import type {
EvaluationResponse,
PeerReviewResponse,
} from '@/api/openapi/models';
import type { PeerReviewResponse } from '@/api/openapi/models';
import Avatar from '@/components/ui/avatar';
import Button from '@/components/ui/button';
import MoreMenu from '@/components/ui/dropdown/more-menu';
Expand All @@ -20,12 +17,10 @@ import {
} from '@/hooks/queries/peer-review-api';
import { useIsLeader } from '@/stores/useLeaderStore';
import { useUserStore } from '@/stores/useUserStore';
import CreateEvaluationModal from '../modals/create-evaluation-modal';
import DeleteHomeworkModal from '../modals/delete-homework-modal';
import EditHomeworkModal from '../modals/edit-homework-modal';

interface HomeworkDetailContentProps {
groupStudyId: number;
missionId: number;
homeworkId: number;
}
Expand All @@ -37,7 +32,6 @@ export default function HomeworkDetailContent({
const router = useRouter();
const searchParams = useSearchParams();
const currentUserId = useUserStore((state) => state.memberId);
const isLeader = useIsLeader(currentUserId);
const { data: homework, isLoading: isHomeworkLoading } =
useGetHomework(homeworkId);
const {
Expand Down Expand Up @@ -137,100 +131,32 @@ export default function HomeworkDetailContent({
)}
</div>

{/* 리더 평가 */}
<LeaderEvaluationSection
evaluation={homework.evaluation}
isLeader={isLeader}
homeworkId={homeworkId}
/>

{/* 피어 리뷰 */}
<PeerReviewSection
homeworkId={homeworkId}
peerReviews={peerReviews ?? []}
isLeader={isLeader}
isMyHomework={isMyHomework}
/>
</div>
);
}

interface LeaderEvaluationSectionProps {
evaluation?: EvaluationResponse;
isLeader: boolean;
homeworkId: number;
}

function LeaderEvaluationSection({
evaluation,
isLeader,
homeworkId,
}: LeaderEvaluationSectionProps) {
return (
<div className="flex flex-col gap-200">
<span className="font-designer-18b text-text-default">리더 평가</span>

<div className="border-border-default rounded-100 flex flex-col items-center justify-center gap-200 border p-400">
{evaluation ? (
<EvaluationResult evaluation={evaluation} />
) : (
<EvaluationPending isLeader={isLeader} homeworkId={homeworkId} />
)}
</div>
</div>
);
}

function EvaluationResult({ evaluation }: { evaluation: EvaluationResponse }) {
return (
<div className="flex w-full flex-col gap-200">
<div className="flex items-center gap-200">
<span className="font-designer-14b text-text-default">평가 등급</span>
<span className="text-text-brand font-designer-16b">
{evaluation.grade?.gradeLabel ?? '-'}
</span>
</div>
<div className="flex flex-col gap-100">
<span className="font-designer-14b text-text-default">평가 코멘트</span>
<p className="text-text-default font-designer-14r wrap-anywhere whitespace-pre-wrap">
{evaluation.comment}
</p>
</div>
</div>
);
}

function EvaluationPending({
isLeader,
homeworkId,
}: {
isLeader: boolean;
homeworkId: number;
}) {
return (
<>
<span className="text-text-subtlest font-designer-14r">
아직 평가하지 않은 과제입니다.
</span>
{isLeader && <CreateEvaluationModal homeworkId={homeworkId} />}
</>
);
}

interface PeerReviewSectionProps {
homeworkId: number;
peerReviews: PeerReviewResponse[];
isLeader: boolean;
isMyHomework: boolean;
}

function PeerReviewSection({
homeworkId,
peerReviews,
isLeader,
isMyHomework,
}: PeerReviewSectionProps) {
const canWriteReview = !isLeader && !isMyHomework;
const currentUserId = useUserStore((state) => state.memberId);
const isMissionCreator = useIsLeader(currentUserId);

// 자기 과제가 아니고, 미션 생성자(리더)가 아닌 경우에만 리뷰 작성 가능
const canWriteReview = !isMyHomework && !isMissionCreator;
const [reviewText, setReviewText] = useState('');
const { mutate: createPeerReview, isPending } = useCreatePeerReview();

Expand Down Expand Up @@ -273,7 +199,7 @@ function PeerReviewSection({
</div>
)}

{/* 리뷰 입력 - 리더가 아니고 자기 과제가 아닌 경우에만 표시 */}
{/* 리뷰 입력 - 자기 과제가 아닌 경우에만 표시 */}
{canWriteReview && (
<PeerReviewInput
value={reviewText}
Expand All @@ -300,8 +226,7 @@ function PeerReviewItem({ review, homeworkId }: PeerReviewItemProps) {

const { mutate: updatePeerReview, isPending: isUpdating } =
useUpdatePeerReview();
const { mutate: deletePeerReview, isPending: isDeleting } =
useDeletePeerReview();
const { mutate: deletePeerReview } = useDeletePeerReview();

const isMyReview = review.reviewerId === currentUserId;

Expand Down
30 changes: 3 additions & 27 deletions src/components/contents/mission-detail-content.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
'use client';

import { useRouter, useSearchParams } from 'next/navigation';
import { useMemo } from 'react';

import type { HomeworkDetailResponseDto } from '@/api/openapi/models';
import Avatar from '@/components/ui/avatar';
import Badge from '@/components/ui/badge';
import Progress from '@/components/ui/progress';
import { useGetMission } from '@/hooks/queries/mission-api';
import { useIsLeader } from '@/stores/useLeaderStore';
import { useUserStore } from '@/stores/useUserStore';
import MyHomeworkStatus from '../card/my-homework-status-card';

interface MissionDetailContentProps {
groupStudyId: number;
missionId: number;
}

Expand All @@ -24,22 +20,12 @@ const HOMEWORK_STATUS_CONFIG = {
} as const;

export default function MissionDetailContent({
groupStudyId,
missionId,
}: MissionDetailContentProps) {
const router = useRouter();
const searchParams = useSearchParams();
const memberId = useUserStore((state) => state.memberId);
const isLeader = useIsLeader(memberId);

const { data: mission, isLoading, refetch } = useGetMission(missionId);

// homeworks에서 내 과제 정보 찾기
const myHomework = useMemo(() => {
if (!mission?.homeworks || !memberId) return null;

return mission.homeworks.find((hw) => hw.submitterId === memberId) ?? null;
}, [mission?.homeworks, memberId]);
const { data: mission, isLoading } = useGetMission(missionId);

const handleSelectHomework = (homeworkId: number) => {
const params = new URLSearchParams(searchParams.toString());
Expand All @@ -56,8 +42,6 @@ export default function MissionDetailContent({
(mission.maxHomeworkSubmissionCount ?? 1)) *
100;

const isMissionClosed = mission.status === 'ENDED';

return (
<div className="flex flex-col gap-400">
{/* 미션 상세 정보 */}
Expand All @@ -77,16 +61,8 @@ export default function MissionDetailContent({
</div>
</div>

{/* 내 과제 현황 - 리더가 아닐 경우에만 표시 */}
{!isLeader && (
<MyHomeworkStatus
missionId={missionId}
myHomework={myHomework}
isMissionClosed={isMissionClosed}
onSelectHomework={handleSelectHomework}
onRefetch={refetch}
/>
)}
{/* 내 과제 현황 */}
<MyHomeworkStatus missionId={missionId} />

{/* 제출 현황 */}
<div className="flex flex-col gap-300">
Expand Down
6 changes: 1 addition & 5 deletions src/components/section/mission-section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ export default function MissionSection({ groupStudyId }: MissionSectionProps) {
</button>

<HomeworkDetailContent
groupStudyId={groupStudyId}
missionId={Number(missionId)}
homeworkId={Number(homeworkId)}
/>
Expand Down Expand Up @@ -147,10 +146,7 @@ export default function MissionSection({ groupStudyId }: MissionSectionProps) {
미션 상세
</button>

<MissionDetailContent
groupStudyId={groupStudyId}
missionId={Number(missionId)}
/>
<MissionDetailContent missionId={Number(missionId)} />
</PageContainer>
);
}
Expand Down
5 changes: 4 additions & 1 deletion src/hooks/queries/group-study-homework-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,13 @@ export const useSubmitHomework = () => {

return data.content;
},
onSuccess: async () => {
onSuccess: async (_, variables) => {
await queryClient.invalidateQueries({
queryKey: ['homeworks'],
});
await queryClient.invalidateQueries({
queryKey: ['mission', variables.missionId],
});
},
});
};
Expand Down
Loading