Skip to content

멘토스터디 / 그룹스터디 미션 평가 노출 로직 수정 및 JS 로드 크기 개선#541

Merged
HA-SEUNG-JEONG merged 15 commits into
developfrom
fix/mission
Apr 7, 2026
Merged

멘토스터디 / 그룹스터디 미션 평가 노출 로직 수정 및 JS 로드 크기 개선#541
HA-SEUNG-JEONG merged 15 commits into
developfrom
fix/mission

Conversation

@HA-SEUNG-JEONG

@HA-SEUNG-JEONG HA-SEUNG-JEONG commented Apr 7, 2026

Copy link
Copy Markdown
Contributor

🌱 연관된 이슈

☘️ 작업 내용

🍀 참고사항

스크린샷 (선택)

Summary by CodeRabbit

  • 새로운 기능

    • 과제 평가 모달 추가: 리더가 등급과 의견 입력 후 제출 가능
    • 과제 상세에 리더용 평가 섹션 노출 제어 추가
  • UI 개선

    • 과제 상태 메시지 세분화: 미제출/미오픈/제출마감 각각 별도 안내 문구 표시
    • 과제 카드 클릭 및 편집·삭제 모달 동작 개선
    • 마감일 텍스트 정렬 개선
  • 리팩터링 / 성능

    • 일부 콘텐츠(마크다운·상세 컴포넌트) 클라이언트 지연 로딩 적용
  • 버그 수정

    • 날짜 비교 로직 정규화로 일자 처리 정확도 향상

@HA-SEUNG-JEONG HA-SEUNG-JEONG self-assigned this Apr 7, 2026
@vercel

vercel Bot commented Apr 7, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
study-platform-client-dev Error Error Apr 7, 2026 4:38pm

@coderabbitai

coderabbitai Bot commented Apr 7, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

과제 평가 모달(CreateEvaluationModal) 추가, HomeworkDetailContent에 리더 평가 섹션 연동, 클라이언트 전용 동적 로드(ssr: false)로 변경, 미션/홈워크 카드의 클릭·마크업 및 제출 상태 메시지 분리, 미션 상세의 진행 계산 보정이 적용되었습니다.

Changes

Cohort / File(s) Summary
평가 기능 추가
src/components/common/modals/create-evaluation-modal.tsx, src/components/contents/homework-detail-content.tsx
CreateEvaluationModal 컴포넌트 추가(react-hook-form + Zod, 등급 조회, 평가 제출 mutation). HomeworkDetailContent에 showLeaderEvaluation?: boolean prop 추가 및 LeaderEvaluationSection 연동.
동적 임포트 (클라이언트 전용)
src/components/section/group-study-info-section.tsx, src/components/section/premium-study-info-section.tsx, src/components/section/mission-section.tsx
MarkdownContent, HomeworkDetailContent, MissionDetailContentnext/dynamic({ ssr: false })로 클라이언트 동적 로드하도록 변경.
미션 카드 마크업/클릭 처리 변경
src/components/card/mission-card.tsx
리더 클릭 처리 재구성: stopActionAreaPropagation 제거, 버튼 내부에 MissionCardContent 유지, 편집/삭제 모달 컨테이너를 버튼의 형제로 분리; deadline 텍스트에 text-left 클래스 추가.
홈워크 제출 상태 메시지 분리
src/components/card/my-homework-status-card.tsx
제출 상태 플래그 분리(isSubmissionNotOpened, isSubmissionOpen, isSubmissionClosed) 및 미제출 안내 문구를 상태별로 독립 렌더링; 모달 트리거는 isSubmissionOpen 유지.
미션 상세 계산 안전성 개선
src/components/contents/mission-detail-content.tsx
maxCount 로컬 도입으로 progressValue 분모가 최소 1이 되도록 보정(0/Falsy 대비).
유틸: 날짜 정규화 및 비활성일자 로직 개선
src/utils/time.ts
toDateOnly 헬퍼 추가 및 createDisabledDateMatcherForMission 리팩토링으로 날짜 비교를 날짜 단위로 정규화하고 비교 로직 간소화.
props/타입 변경
src/components/section/mission-section.tsx, src/components/contents/homework-detail-content.tsx
MissionSectionProps에서 showMyHomework?: boolean 제거. MissionSection에서 스터디 상세 조회를 추가해 isPremiumStudy 산출 후 HomeworkDetailContentshowLeaderEvaluation={isLeaderProp && isPremiumStudy} 전달.

Sequence Diagram

sequenceDiagram
    actor User
    participant Modal as CreateEvaluationModal
    participant Grades as useGetMissionEvaluationGrades()
    participant Form as CreateEvaluationForm
    participant API as useCreateEvaluation()
    participant Server as Backend
    participant Toast as Toast

    User->>Modal: "과제 평가하기" 클릭
    Modal->>Grades: 등급 목록 요청
    Grades-->>Modal: 등급 목록 응답
    User->>Form: 등급 선택 및 코멘트 입력
    Form->>Form: Zod 유효성 검사
    User->>Modal: "평가 완료" 클릭 (form 제출)
    Modal->>API: mutate(homeworkId, {gradeCode, comment})
    API->>Server: POST /evaluations
    Server-->>API: 성공 응답
    API-->>Modal: 성공
    Modal->>Toast: 성공 토스트 표시
    Modal->>Modal: 모달 닫기
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22분

Possibly related PRs

Poem

🐰 모달 톡, 등급이 후다닥 모여요,
코멘트 한 줄로 마음을 나누고,
동적 로딩은 살짝 숨어서 빛나고,
상태는 세 갈래로 또렷이 갈라지고,
토끼가 깡충—평가 축하 당근 드려요! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 풀 리퀘스트 제목이 변경 사항의 주요 내용과 부합합니다. 멘토스터디/그룹스터디의 미션 평가 노출 로직 수정과 JS 로드 크기 개선이라는 두 가지 핵심 변경사항을 명확하게 요약하고 있습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/mission

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components/card/my-homework-status-card.tsx (1)

37-55: ⚠️ Potential issue | 🟠 Major

미션 상태 분기 누락으로 미제출 안내 문구가 비어 보일 수 있습니다.

mission.statusEVALUATION_COMPLETED인 경우(Line 37-38) 현재 세 조건이 모두 false가 되어(Line 48, Line 51, Line 54) 상태 안내가 전혀 렌더링되지 않습니다. 미제출 사용자에게 빈 상태 카드가 노출됩니다. 상태-문구를 단일 매핑으로 통합하고 기본(fallback) 문구를 두는 방식으로 분기 누락을 막아주세요.

💡 제안 수정안
-  const isSubmissionOpen = mission?.status === 'IN_PROGRESS';
-  const isSubmissionNotOpened = mission?.status === 'NOT_STARTED';
-  const isSubmissionEnded = mission?.status === 'ENDED';
+  const isSubmissionOpen = mission?.status === 'IN_PROGRESS';
+  const submissionMessageByStatus: Record<string, string> = {
+    IN_PROGRESS: '아직 과제를 제출하지 않았습니다.',
+    NOT_STARTED: '과제 제출 기간이 아닙니다.',
+    ENDED: '제출 기간이 종료되었습니다.',
+    EVALUATION_COMPLETED: '제출 기간이 종료되었습니다.',
+  };
+  const submissionMessage =
+    (mission?.status && submissionMessageByStatus[mission.status]) ??
+    '과제 상태를 확인할 수 없습니다.';

@@
-          <span className="text-text-subtlest font-designer-14r">
-            {isSubmissionOpen && '아직 과제를 제출하지 않았습니다.'}
-          </span>
-          <span className="text-text-subtlest font-designer-14r">
-            {isSubmissionNotOpened && '과제 제출 기간이 아닙니다.'}
-          </span>
-          <span className="text-text-subtlest font-designer-14r">
-            {isSubmissionEnded && '제출 기간이 종료되었습니다.'}
-          </span>
+          <span className="text-text-subtlest font-designer-14r">
+            {submissionMessage}
+          </span>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/card/my-homework-status-card.tsx` around lines 37 - 55, The
card currently computes booleans (isSubmissionNotOpened, isSubmissionEnded, and
isSubmissionOpen) and then renders three separate conditional spans which all
stay false for mission.status === 'EVALUATION_COMPLETED', leaving an empty card;
replace these separate conditionals in the NOT_SUBMITTED branch with a single
status-to-message mapping (e.g., a map keyed by mission.status) and render the
mapped message or a default fallback string when no key matches; update
references to mission.status and the booleans (isSubmissionNotOpened,
isSubmissionEnded, isSubmissionOpen) in the render path to use the map lookup so
the NOT_SUBMITTED UI always shows a message.
🧹 Nitpick comments (2)
src/components/section/premium-study-info-section.tsx (1)

11-11: 주석 처리된 import를 제거하세요.

사용하지 않는 주석 처리된 import가 남아있습니다. 동적 import로 대체되었으므로 이 줄을 삭제해주세요.

🧹 제안된 수정
-// import MarkdownContent from '@/components/common/ui/editor/markdown-content';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/section/premium-study-info-section.tsx` at line 11, 주석 처리된
사용하지 않는 import 문을 제거하세요: 파일의 "// import MarkdownContent from
'@/components/common/ui/editor/markdown-content';" 라인을 삭제하여 정리하고, 컴포넌트 내에서 이미 동적
import로 로드되는 MarkdownContent 참조(또는 관련 동적 import 호출)를 유지해 중복 import 주석을 남기지 않도록
하세요.
src/components/section/group-study-info-section.tsx (1)

13-13: 주석 처리된 import를 제거하세요.

premium-study-info-section.tsx와 동일하게, 사용하지 않는 주석 처리된 import를 삭제해주세요.

🧹 제안된 수정
-// import MarkdownContent from '@/components/common/ui/editor/markdown-content';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/section/group-study-info-section.tsx` at line 13, 파일
src/components/section/group-study-info-section.tsx에 남아있는 주석 처리된 import 문을
제거하세요; 구체적으로 "// import MarkdownContent from
'@/components/common/ui/editor/markdown-content';" 라인(참조 심볼: MarkdownContent)을
삭제하여 premium-study-info-section.tsx와 동일하게 사용하지 않는 주석된 import를 정리합니다.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/common/modals/create-evaluation-modal.tsx`:
- Around line 112-117: gradeOptions can become undefined while
useGetMissionEvaluationGrades() is still loading, causing downstream consumers
like GroupItems to receive undefined; change the expression that builds
gradeOptions (currently referencing grades and mapping into value/label) to
safely handle missing data by using a fallback empty array (e.g., operate on
(grades ?? []) or default to []) so gradeOptions is always an array, preserving
the same sort/map logic and label formatting, and ensure GroupItems is passed
this guaranteed-array gradeOptions.

In `@src/components/contents/homework-detail-content.tsx`:
- Around line 160-165: Change the mission-status check that controls rendering
of the leader evaluation UI: in the conditional using showLeaderEvaluation and
mission.status (which currently compares to 'EVALUATION_COMPLETED'), update it
to check for 'ENDED' instead so LeaderEvaluationSection (which passes evaluation
and homeworkId and allows CreateEvaluationModal when !evaluation) only renders
after submission deadline; ensure the condition reads mission.status === 'ENDED'
alongside the existing showLeaderEvaluation guard.

In `@src/components/section/mission-section.tsx`:
- Around line 176-179: The bug is that canAccessAll can be boolean | undefined
(since isMember and isLeaderProp are optional), causing showMyHomework !== false
to evaluate true for undefined and incorrectly show "내 과제 현황"; fix by making
canAccessAll an explicit boolean or changing the component check: either coerce
the value where it’s computed using canAccessAll = !!(isMember || isLeaderProp)
so MissionDetailContent always receives a boolean, or keep the prop but update
MissionDetailContent to only show homework when showMyHomework === true (change
the conditional that checks showMyHomework to a strict equality).

---

Outside diff comments:
In `@src/components/card/my-homework-status-card.tsx`:
- Around line 37-55: The card currently computes booleans
(isSubmissionNotOpened, isSubmissionEnded, and isSubmissionOpen) and then
renders three separate conditional spans which all stay false for mission.status
=== 'EVALUATION_COMPLETED', leaving an empty card; replace these separate
conditionals in the NOT_SUBMITTED branch with a single status-to-message mapping
(e.g., a map keyed by mission.status) and render the mapped message or a default
fallback string when no key matches; update references to mission.status and the
booleans (isSubmissionNotOpened, isSubmissionEnded, isSubmissionOpen) in the
render path to use the map lookup so the NOT_SUBMITTED UI always shows a
message.

---

Nitpick comments:
In `@src/components/section/group-study-info-section.tsx`:
- Line 13: 파일 src/components/section/group-study-info-section.tsx에 남아있는 주석 처리된
import 문을 제거하세요; 구체적으로 "// import MarkdownContent from
'@/components/common/ui/editor/markdown-content';" 라인(참조 심볼: MarkdownContent)을
삭제하여 premium-study-info-section.tsx와 동일하게 사용하지 않는 주석된 import를 정리합니다.

In `@src/components/section/premium-study-info-section.tsx`:
- Line 11: 주석 처리된 사용하지 않는 import 문을 제거하세요: 파일의 "// import MarkdownContent from
'@/components/common/ui/editor/markdown-content';" 라인을 삭제하여 정리하고, 컴포넌트 내에서 이미 동적
import로 로드되는 MarkdownContent 참조(또는 관련 동적 import 호출)를 유지해 중복 import 주석을 남기지 않도록
하세요.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 48c8563f-c893-42f8-8ecb-e78c34cf7b45

📥 Commits

Reviewing files that changed from the base of the PR and between 69d7efa and 364995f.

📒 Files selected for processing (7)
  • src/components/card/mission-card.tsx
  • src/components/card/my-homework-status-card.tsx
  • src/components/common/modals/create-evaluation-modal.tsx
  • src/components/contents/homework-detail-content.tsx
  • src/components/section/group-study-info-section.tsx
  • src/components/section/mission-section.tsx
  • src/components/section/premium-study-info-section.tsx

Comment thread src/components/common/modals/create-evaluation-modal.tsx Outdated
Comment thread src/components/contents/homework-detail-content.tsx Outdated
Comment thread src/components/section/mission-section.tsx
"EVALUATION_COMPLETED" 에서 "ENDED"로 수정

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/contents/homework-detail-content.tsx`:
- Around line 465-467: The paragraph currently renders evaluation.comment
directly which leaves the UI empty when evaluation.comment is undefined or an
empty string; update the render in the HomeworkDetailContent component so the
<p> that references evaluation.comment uses an explicit fallback (same style as
the grade fallback) — e.g. replace direct use of evaluation.comment with a check
for null/empty and render a default string like "평가 없음" or the existing grade
fallback value instead; ensure the element and its classes (the <p> with
className "text-text-default font-designer-14r wrap-anywhere
whitespace-pre-wrap") still preserve whitespace formatting.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: cd6ba456-ef3b-474e-8293-f73b038000c2

📥 Commits

Reviewing files that changed from the base of the PR and between ea7f6ac and e2b0427.

📒 Files selected for processing (2)
  • src/components/card/my-homework-status-card.tsx
  • src/components/contents/homework-detail-content.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/card/my-homework-status-card.tsx

Comment thread src/components/contents/homework-detail-content.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/utils/time.ts`:
- Around line 124-127: Fix camelCase typos by renaming existingmissionStartDate
and existingmissionEndDate to existingMissionStartDate and
existingMissionEndDate, and make toDateOnly robust for KST/ISO date strings by
importing parseISO and isValid from date-fns, using parseISO when the input is a
string (fallback to new Date for Date inputs), validate with isValid, then zero
out time via setHours(0,0,0,0); ensure callers handle parse failures
appropriately (throw or return null) and update any references to the renamed
variables (e.g., existingMissionStartDate, existingMissionEndDate) and the
toDateOnly function signature accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0a316cc4-91eb-4237-98e3-952559d9e141

📥 Commits

Reviewing files that changed from the base of the PR and between 95a849b and b26e8b5.

📒 Files selected for processing (1)
  • src/utils/time.ts

Comment thread src/utils/time.ts
Comment on lines +124 to +127
const toDateOnly = (date: Date | string): Date => {
const d = new Date(date);
d.setHours(0, 0, 0, 0);
return d;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

JavaScript에서 new Date('YYYY-MM-DD')는 UTC로 파싱되나요? date-fnsparseISO('YYYY-MM-DD')와 타임존 동작 차이를 공식 문서 기준으로 비교해 주세요.

💡 Result:

결론: new Date('YYYY-MM-DD')UTC 기준으로(자정 UTC) 파싱됩니다. 반면 date-fnsparseISO('YYYY-MM-DD')로컬 타임존 기준(로컬 자정)으로 결과 Date를 만듭니다.


1) JavaScript new Date('YYYY-MM-DD') (=Date.parse 규칙)

MDN의 “Date time string format” 설명에 따르면:

  • 타임존 오프셋이 없는 경우
    • date-only 형식(YYYY-MM-DD)은 UTC로 해석
    • date-time 형식(YYYY-MM-DDTHH:mm:ss)은 로컬 타임존으로 해석
  • 그리고 이 동작은 “역사적 스펙 오류(ISO 8601과 불일치)지만 웹 호환성 때문에 유지”라고 명시돼 있습니다. (developer.mozilla.org)

또한 MDN Date.parse() 예시는 date-only 문자열이 UTC를 암시한다고 직접 말합니다. (developer.mozilla.org)

따라서:

  • new Date('2019-01-01')2019-01-01T00:00:00.000Z (UTC 자정) 로 파싱
  • 이 값을 toString()(로컬 표시)로 보면, 로컬이 UTC보다 뒤(예: 미국)인 경우 전날 저녁으로 보일 수 있습니다(표시 변환 때문).

2) date-fns parseISO('YYYY-MM-DD')

date-fnsparseISO 구현(공식 GitHub 소스 코드 JSDoc)에:

  • @returns The parsed date in the local time zone (로컬 타임존에서의 파싱 결과를 반환) 이라고 명시돼 있습니다. (github.com)

또한 구현 로직상 입력에 timezone이 없으면 UTC 컴포넌트를 꺼내서(getUTC*) 결과 Date에 로컬 시간으로 세팅해 **“로컬 자정의 같은 달력 날짜”**가 되도록 처리합니다. (github.com)
(입력에 Z 또는 +09:00 같은 timezone이 있으면 그 오프셋을 적용해 타임스탬프를 계산합니다. (github.com))

따라서:

  • parseISO('2019-01-01')로컬 타임존의 2019-01-01 00:00:00 에 해당하는 Date

3) 차이 요약 (공식 문서/소스 기준)

입력 new Date(input) / Date.parse(input) parseISO(input)
YYYY-MM-DD (date-only) UTC로 해석 (developer.mozilla.org) 로컬 타임존 결과 (github.com)
YYYY-MM-DDTHH:mm:ss (오프셋 없음) 로컬로 해석 (developer.mozilla.org) (timezone 없으면) 로컬 타임존 결과 (github.com)
...Z / ...+09:00 (오프셋 있음) 오프셋 반영해 타임스탬프 계산(UTC 기준) (developer.mozilla.org) 오프셋 파싱 후 타임스탬프 계산 (github.com)

원하시면, 사용 중인 환경(브라우저/Node, 사용자의 타임존 예: America/New_York)을 기준으로 toString(), toISOString()까지 포함한 “왜 하루가 밀려 보이는지” 재현 코드도 함께 정리해 드릴게요.

Citations:


🏁 Script executed:

# 1. 파일 전체 내용 확인 (크기 확인 후 읽기)
wc -l src/utils/time.ts

Repository: code-zero-to-one/study-platform-client

Length of output: 103


🏁 Script executed:

# 2. 함수 전체 구현 확인
sed -n '100,180p' src/utils/time.ts

Repository: code-zero-to-one/study-platform-client

Length of output: 2287


🏁 Script executed:

# 3. getKoreaDate 구현 확인
grep -n "getKoreaDate\|export.*const getKoreaDate" src/utils/time.ts

Repository: code-zero-to-one/study-platform-client

Length of output: 503


🏁 Script executed:

# 4. date-fns import 확인
head -30 src/utils/time.ts | grep -E "import.*from.*date-fns"

Repository: code-zero-to-one/study-platform-client

Length of output: 119


🏁 Script executed:

# 5. mission 관련 타입 정의 확인 (startDate, endDate 형식)
find src -name "*.ts" -o -name "*.tsx" | xargs grep -l "interface.*Mission\|type.*Mission" | head -5

Repository: code-zero-to-one/study-platform-client

Length of output: 329


🏁 Script executed:

# 6. 실제 데이터 흐름: createDisabledDateMatcherForMission 호출 지점 확인
rg "createDisabledDateMatcherForMission" -A 3 -B 3 | head -40

Repository: code-zero-to-one/study-platform-client

Length of output: 2981


🏁 Script executed:

# getKoreaDate 상세 구현 확인
sed -n '38,50p' src/utils/time.ts

Repository: code-zero-to-one/study-platform-client

Length of output: 473


🏁 Script executed:

# 백엔드 API 응답 타입 확인
cat src/api/openapi/models/mission-list-response-schema.ts | head -50

Repository: code-zero-to-one/study-platform-client

Length of output: 827


🏁 Script executed:

# 실제 데이터 흐름: create-mission-modal에서 studyStartDate 출처 확인
grep -n "studyStartDate\|studyEndDate" src/components/common/modals/create-mission-modal.tsx | head -10

Repository: code-zero-to-one/study-platform-client

Length of output: 471


🏁 Script executed:

# Mission 상세 타입 확인 - startDate 형식 명시
grep -A 30 "interface.*MissionListResponse\|export.*MissionListResponse" src/api/openapi/models/mission-list-response-schema.ts | head -40

Repository: code-zero-to-one/study-platform-client

Length of output: 383


🏁 Script executed:

# Mission 상세 API 모델 확인 - mission-api.ts 에서 date 필드 타입
cat src/api/openapi/models/mission-creation-request.ts

Repository: code-zero-to-one/study-platform-client

Length of output: 738


🏁 Script executed:

# useGroupStudyDetailQuery 데이터 형식 확인
rg "useGroupStudyDetailQuery\|basicInfo" -A 5 src/hooks/queries/use-study-query.ts | head -30

Repository: code-zero-to-one/study-platform-client

Length of output: 64


🏁 Script executed:

# 실제 백엔드 응답 예시가 있는지 스키마 확인
find src -name "*.ts" | xargs grep -l "startDate.*string\|endDate.*string" | head -5

Repository: code-zero-to-one/study-platform-client

Length of output: 313


🏁 Script executed:

# 최종 확인: 백엔드 응답 데이터 형식 추적
# mission 객체가 실제로 어떤 format으로 오는지 테스트 또는 예시 찾기
rg "mission\.(startDate|endDate)" -B 3 -A 3 src/components/common/modals/ | head -50

Repository: code-zero-to-one/study-platform-client

Length of output: 64


🏁 Script executed:

# API 문서 또는 타입 정의에서 실제 date format 명시 확인
find src/api/openapi/models -name "*mission*" -type f | xargs grep -l "startDate\|endDate"

Repository: code-zero-to-one/study-platform-client

Length of output: 229


🏁 Script executed:

# 전체 파일 최종 검토: 실제 Line 161-162 오타 재확인
sed -n '155,170p' src/utils/time.ts

Repository: code-zero-to-one/study-platform-client

Length of output: 646


🏁 Script executed:

# 백엔드 실제 응답 형식 최종 추적: mission-list-response.ts 상세 확인
cat src/api/openapi/models/mission-list-response.ts | head -80

Repository: code-zero-to-one/study-platform-client

Length of output: 995


🏁 Script executed:

# study.basicInfo.startDate 실제 타입 추적
find src/api/openapi/models -name "*study*" -o -name "*group*" | xargs cat 2>/dev/null | grep -A 20 "startDate\|endDate" | head -40

Repository: code-zero-to-one/study-platform-client

Length of output: 1038


🏁 Script executed:

# 현재 date-fns 라이브러리 버전 확인 (parseISO 사용 가능 여부)
grep "date-fns" package.json

Repository: code-zero-to-one/study-platform-client

Length of output: 107


Line 161-162의 카멜케이스 오류 수정과 KST 기준 날짜 파싱 일관성 필요.

Line 161-162에서 변수명 existingmissionStartDate, existingmissionEndDate (첫 글자 소문자)이 발견되었습니다. 또한 new Date('YYYY-MM-DD') 형식의 문자열 파싱은 UTC 기준으로 이루어지므로, 비-KST 환경에서 클라이언트 시간으로 렌더링될 때 로컬 날짜가 하루 밀릴 수 있습니다. 함수가 KST 기준 로직을 의도했다면, date-fnsparseISO 사용이나 명시적 타임존 처리가 필요합니다.

제안 수정안
-const toDateOnly = (date: Date | string): Date => {
-  const d = new Date(date);
-  d.setHours(0, 0, 0, 0);
-  return d;
-};
+const toDateOnly = (input: Date | string): Date => {
+  const source =
+    typeof input === 'string' ? parseISO(input) : new Date(input);
+  if (!isValid(source)) return new Date(NaN);
+  return new Date(
+    source.getFullYear(),
+    source.getMonth(),
+    source.getDate(),
+  );
+};
-        const existingmissionStartDate = toDateOnly(
-          mission.startDate,
-        ).getTime();
-
-        const existingmissionEndDate = toDateOnly(mission.endDate).getTime();
+        const existingMissionStartDate = toDateOnly(mission.startDate);
+        const existingMissionEndDate = toDateOnly(mission.endDate);
+        if (
+          !isValid(existingMissionStartDate) ||
+          !isValid(existingMissionEndDate)
+        )
+          continue;

         if (
-          candidateTime >= existingmissionStartDate &&
-          candidateTime <= existingmissionEndDate
+          candidateTime >= existingMissionStartDate.getTime() &&
+          candidateTime <= existingMissionEndDate.getTime()
         )
           return true;

parseISO, isValiddate-fns에서 import 필요합니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/utils/time.ts` around lines 124 - 127, Fix camelCase typos by renaming
existingmissionStartDate and existingmissionEndDate to existingMissionStartDate
and existingMissionEndDate, and make toDateOnly robust for KST/ISO date strings
by importing parseISO and isValid from date-fns, using parseISO when the input
is a string (fallback to new Date for Date inputs), validate with isValid, then
zero out time via setHours(0,0,0,0); ensure callers handle parse failures
appropriately (throw or return null) and update any references to the renamed
variables (e.g., existingMissionStartDate, existingMissionEndDate) and the
toDateOnly function signature accordingly.

@HA-SEUNG-JEONG HA-SEUNG-JEONG merged commit 957f8a8 into develop Apr 7, 2026
7 of 8 checks passed
@HA-SEUNG-JEONG HA-SEUNG-JEONG deleted the fix/mission branch April 7, 2026 12:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant