Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,29 @@ const RecruitEditTab = () => {

const now = new Date();

setRecruitmentStart((prev) => prev ?? initialStart ?? now);
setRecruitmentEnd((prev) => prev ?? initialEnd ?? now);
setRecruitmentStart((prev) => prev ?? correctResponseKoreanDate(initialStart) ?? now);
setRecruitmentEnd((prev) => prev ?? correctResponseKoreanDate(initialEnd) ?? now);
setRecruitmentTarget((prev) => prev || clubDetail.recruitmentTarget || '');
setDescription((prev) => prev || clubDetail.description || '');
}, [clubDetail]);

const correctRequestKoreanDate = (date: Date | null): Date | null => {
if (!date) return null;
return new Date(date?.getTime() + 9 * 60 * 60 * 1000);
}

const correctResponseKoreanDate = (date: Date | null): Date | null => {
if (!date) return null;
return new Date(date?.getTime() - 9 * 60 * 60 * 1000);
}

const handleUpdateClub = async () => {
if (!clubDetail) return;

const updatedData = {
id: clubDetail.id,
recruitmentStart: recruitmentStart?.toISOString(),
recruitmentEnd: recruitmentEnd?.toISOString(),
recruitmentStart: correctRequestKoreanDate(recruitmentStart)?.toISOString(),
recruitmentEnd: correctRequestKoreanDate(recruitmentEnd)?.toISOString(),
Comment on lines +53 to +54
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

null 시 undefined 전송 방지 및 DTO 계약 정합성 확인

현재 구현은 Date | null일 때 ?.toISOString()undefined를 생성합니다. API가 부분 업데이트에서 undefined를 무시하는지 혹은 null을 요구하는지에 따라 문제가 될 수 있습니다. 안전하게 조건부 스프레드로 키 자체를 생략하는 방식을 권장합니다.

-      recruitmentStart: correctRequestKoreanDate(recruitmentStart)?.toISOString(),
-      recruitmentEnd: correctRequestKoreanDate(recruitmentEnd)?.toISOString(),
+      ...(recruitmentStart
+        ? { recruitmentStart: correctRequestKoreanDate(recruitmentStart).toISOString() }
+        : {}),
+      ...(recruitmentEnd
+        ? { recruitmentEnd: correctRequestKoreanDate(recruitmentEnd).toISOString() }
+        : {}),

아래 스크립트로 DTO 타입과 훅 시그니처를 확인해 주세요. API가 string | null을 요구한다면, 위 스프레드 대신 : null을 명시하도록 바꾸어야 합니다.


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 업데이트 훅과 DTO 타입 확인
rg -n -C3 'useUpdateClubDescription' --type ts
rg -n -C3 'interface .*Update.*Club.*|type .*Update.*Club.*' --type ts

# 서버 요청 바디에서 recruitment(Start|End) 타입 사용 위치
rg -n -C3 '\brecruitment(Start|End)\b' --type ts | sed -n '1,200p'

Length of output: 2639


아래 스크립트로 ClubDescription 타입 정의와 updateClubDescription API 구현을 확인해주세요.


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# ClubDescription 타입 정의 확인
type_file=$(rg -l -g 'frontend/src/types/**' 'export (interface|type) ClubDescription' | head -n1)
echo "Type file: $type_file"
sed -n '1,200p' "$type_file"

# updateClubDescription API 구현 확인
api_file=$(rg -l -g 'frontend/src/apis/**' 'export function updateClubDescription' | head -n1)
if [ -z "$api_file" ]; then
  api_file=$(rg -l -g 'frontend/src/apis/**' 'const updateClubDescription' | head -n1)
fi
echo "API file: $api_file"
sed -n '1,200p' "$api_file"

Length of output: 1097


아직 updateClubDescription 구현 위치를 찾지 못했습니다. API 파일 경로를 재확인하기 위해 아래 스크립트를 실행해 주세요.


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# frontend/src/apis 디렉터리 내 모든 ts/tsx 파일 중 updateClubDescription 정의 검색
rg -n --type ts --type tsx 'updateClubDescription' frontend/src/apis

Length of output: 116


아래 스크립트로 updateClubDescription API 구현 파일을 찾아 시그니처를 확인해 주세요.


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# updateClubDescription.ts 파일 찾기 및 내용 출력
api_file=$(find frontend/src/apis -type f -name 'updateClubDescription.ts' | head -n1)
if [ -z "$api_file" ]; then
  echo "updateClubDescription.ts 파일을 찾을 수 없습니다."
  exit 1
fi
echo "API 파일: $api_file"
sed -n '1,200p' "$api_file"

Length of output: 1363


모집 기간 필드가 DTO에 정의되지 않음 및 null 처리 검토 필요

현재 RecruitEditTab.tsx에서 사용 중인 useUpdateClubDescription 훅은 ClubDescription 타입(id, description)만 허용하며, 실제 API(PUT /api/club/description)도 description만 처리합니다.
따라서 아래와 같이 recruitmentStart/recruitmentEnd를 포함해 호출해도

  • 컴파일 시 Excess property 오류 발생
  • 런타임에 JSON.stringify로 undefined 값은 아예 누락되어 전송되지 않음
  • correctRequestKoreanDate(null) 호출 시 함수 내부 에러 가능 (optional chaining은 .toISOString()만 방어)

아래 위치 확인 후 적절히 수정이 필요합니다.

  • frontend/src/pages/AdminPage/tabs/RecruitEditTab/RecruitEditTab.tsx
  • frontend/src/types/club.ts (ClubDescription)
  • frontend/src/apis/updateClubDescription.ts (/api/club/description)

제안 드리는 수정 예시:

  1. 모집 기간 전용 훅/API 분리 사용

    - updateClubDescription({
    -   id,
    -   description,
    -   recruitmentStart: correctRequestKoreanDate(recruitmentStart)?.toISOString(),
    -   recruitmentEnd: correctRequestKoreanDate(recruitmentEnd)?.toISOString(),
    - });
    + // 모집 기간 업데이트 전용 훅/API 호출
    + updateClubRecruitmentPeriod({
    +   id,
    +   ...(recruitmentStart && { recruitmentStart: correctRequestKoreanDate(recruitmentStart).toISOString() }),
    +   ...(recruitmentEnd && { recruitmentEnd: correctRequestKoreanDate(recruitmentEnd).toISOString() }),
    + });
  2. 단일 엔드포인트로 통합 시 DTO 확장

    + // frontend/src/types/club.ts
    + export interface ClubUpdatePayload {
    +   id: string;
    +   description?: string | null;
    +   recruitmentStart?: string;
    +   recruitmentEnd?: string;
    + }

    그리고 훅과 API 시그니처를 ClubUpdatePayload로 변경해 주십시오.

위 두 가지 중 적합한 방안을 선택해 반영 후 다시 검토 부탁드립니다.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In frontend/src/pages/AdminPage/tabs/RecruitEditTab/RecruitEditTab.tsx around
lines 53-54, you're passing recruitmentStart/recruitmentEnd into a hook that
expects ClubDescription (id, description) which causes TypeScript "excess
property" errors and runtime issues (undefined omitted from JSON and
correctRequestKoreanDate(null) can throw); either (A) stop sending dates to
useUpdateClubDescription and call a dedicated recruitment-date API/hook, or (B)
extend the DTO/type to a ClubUpdatePayload that includes optional
recruitmentStart?: string | null and recruitmentEnd?: string | null, update
frontend/src/types/club.ts to add the new type, change
frontend/src/apis/updateClubDescription.ts and the hook signature to accept that
payload, and in RecruitEditTab guard calls so you only call
correctRequestKoreanDate when value is non-null and only include .toISOString()
after a successful date conversion (i.e., compute correctedDate =
correctRequestKoreanDate(val); if (correctedDate) payload.recruitmentStart =
correctedDate.toISOString()) so no undefined or null slips into JSON.

recruitmentTarget: recruitmentTarget,
description: description,
externalApplicationUrl: clubDetail.externalApplicationUrl ?? '',
Expand Down