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
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Calendar from '@/pages/AdminPage/tabs/RecruitEditTab/components/Calendar/
import Button from '@/components/common/Button/Button';
import InputField from '@/components/common/InputField/InputField';
import { useUpdateClubDescription } from '@/hooks/queries/club/useUpdateClubDescription';
import { parseRecruitmentPeriod } from '@/utils/stringToDate';
import { parseRecruitmentPeriod } from '@/utils/recruitmentPeriodParser.ts';
import { ClubDetail } from '@/types/club';
import { useQueryClient } from '@tanstack/react-query';
import MarkdownEditor from '@/pages/AdminPage/tabs/RecruitEditTab/components/MarkdownEditor/MarkdownEditor';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as Styled from './ClubDetailFooter.styles';
import DeadlineBadge from '@/pages/ClubDetailPage/components/DeadlineBadge/DeadlineBadge';
import ClubApplyButton from '@/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton';
import { parseRecruitmentPeriod } from '@/utils/stringToDate';
import { parseRecruitmentPeriod } from '@/utils/recruitmentPeriodParser.ts';
import getDeadlineText from '@/utils/getDeadLineText';

interface ClubDetailFooterProps {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as Styled from './ClubDetailHeader.styles';
import ClubProfile from '@/pages/ClubDetailPage/components/ClubProfile/ClubProfile';
import ClubApplyButton from '@/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton';
import { parseRecruitmentPeriod } from '@/utils/stringToDate';
import { parseRecruitmentPeriod } from '@/utils/recruitmentPeriodParser.ts';
import getDeadlineText from '@/utils/getDeadLineText';
interface ClubDetailHeaderProps {
name: string;
Expand Down
35 changes: 35 additions & 0 deletions frontend/src/utils/parseRecruitmentPeriod.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { parseRecruitmentPeriod } from './recruitmentPeriodParser.ts';

describe('parseRecruitmentPeriod 함수 테스트', () => {
it('올바른 형식의 날짜를 파싱한다.', () => {
const input = '2024.03.20 14:00 ~ 2024.03.25 18:00';
const result = parseRecruitmentPeriod(input);

expect(result.recruitmentStart).toEqual(new Date('2024-03-20T14:00:00'));
expect(result.recruitmentEnd).toEqual(new Date('2024-03-25T18:00:00'));
});

it('날짜가 기간형식이 아닌 단일 날짜 형식인 경우 null을 반환한다.', () => {
const input = '2024.03.20 14:00';
const result = parseRecruitmentPeriod(input);

expect(result.recruitmentStart).toBeNull();
expect(result.recruitmentEnd).toBeNull();
});

it('빈 문자열이라면 null을 반환한다.', () => {
const input = '';
const result = parseRecruitmentPeriod(input);

expect(result.recruitmentStart).toBeNull();
expect(result.recruitmentEnd).toBeNull();
});

it('날짜 사이 ~가 없다면 null을 반환한다.', () => {
const input = '2024.03.20 14:00 - 2024.03.25 18:00';
const result = parseRecruitmentPeriod(input);

expect(result.recruitmentStart).toBeNull();
expect(result.recruitmentEnd).toBeNull();
});
});
50 changes: 50 additions & 0 deletions frontend/src/utils/recruitmentPeriodParser.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { parseRecruitmentDateString } from './recruitmentPeriodParser.ts';

describe('parseRecruitmentPeriod 함수 테스트', () => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

describe 블록 이름이 실제 테스트하는 함수와 일치하지 않습니다.

describe 블록에서 "parseRecruitmentPeriod 함수 테스트"라고 되어 있지만, 실제로는 parseRecruitmentDateString 함수를 테스트하고 있습니다.

다음과 같이 수정해주세요:

-describe('parseRecruitmentPeriod 함수 테스트', () => {
+describe('parseRecruitmentDateString 함수 테스트', () => {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
describe('parseRecruitmentPeriod 함수 테스트', () => {
describe('parseRecruitmentDateString 함수 테스트', () => {
🤖 Prompt for AI Agents
In frontend/src/utils/recruitmentPeriodParser.test.ts at line 3, the describe
block name incorrectly references "parseRecruitmentPeriod" while the tests are
actually for the function "parseRecruitmentDateString". Rename the describe
block to accurately reflect the tested function by changing the text to
"parseRecruitmentDateString 함수 테스트".

it('날짜와 시간이 포함된 문자열을 Date 객체로 정확히 바꾼다', () => {
const input = '2025.05.25 13:45';
const result = new Date('2025-05-25T13:45:00');
expect(parseRecruitmentDateString(input)).toEqual(result);
Comment on lines +6 to +7
Copy link
Copy Markdown
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

시간대 문제로 인한 테스트 불안정성 가능성을 확인해주세요.

테스트에서 new Date('2025-05-25T13:45:00')와 같이 ISO 문자열로 Date 객체를 생성하고 있는데, 이는 로컬 시간대에 따라 다르게 해석될 수 있습니다. parseRecruitmentDateString 함수도 로컬 시간대를 기준으로 파싱하므로 환경에 따라 테스트가 실패할 수 있습니다.

다음 스크립트로 시간대 문제가 있는지 확인해보겠습니다:

Also applies to: 12-13


🏁 Script executed:

#!/bin/bash
# Description: 테스트 파일의 Date 객체 생성 방식 확인

# Test: Date 객체 생성 패턴 검색
rg -A 2 -B 2 "new Date\(" frontend/src/utils/recruitmentPeriodParser.test.ts

Length of output: 513


🏁 Script executed:

#!/bin/bash
# Retrieve the implementation of parseRecruitmentDateString for timezone behavior analysis
rg -n "parseRecruitmentDateString" -A5 -B5 frontend/src/utils/recruitmentPeriodParser.ts

Length of output: 174


🏁 Script executed:

#!/bin/bash
# Search for parseRecruitmentDateString implementation across the repo
rg -n "parseRecruitmentDateString" -A5 -B5

Length of output: 5713


🏁 Script executed:

#!/bin/bash
# List files in the utils directory
echo "Files in frontend/src/utils:"
ls -1 frontend/src/utils

# Print the content of the parser implementation file(s)
echo -e "\nContent of recruitmentPeriodParser.ts:"
sed -n '1,200p' frontend/src/utils/recruitmentPeriodParser.ts || echo "frontend/src/utils/recruitmentPeriodParser.ts not found"

echo -e "\nContent of recruitmentPeriodParser.ts.ts:"
sed -n '1,200p' frontend/src/utils/recruitmentPeriodParser.ts.ts || echo "frontend/src/utils/recruitmentPeriodParser.ts.ts not found"

Length of output: 1734


테스트의 Date 생성 방식이 로컬 타임존에 종속되어 있어 환경별로 실패할 수 있습니다

ISO 문자열('2025-05-25T13:45:00')로 Date 객체를 만들면 UTC 기준으로 해석되고, date-fnsparse는 로컬 타임존 기준으로 파싱하기에 타임존에 따라 getTime() 값이 달라집니다. 숫자 인자를 사용하는 생성자 호출로 바꿔 로컬 타임존 의존성을 제거해주세요.

수정 위치:

  • frontend/src/utils/recruitmentPeriodParser.test.ts (라인 5–7, 11–13)

제안 드리는 diff:

 it('날짜와 시간이 포함된 문자열을 Date 객체로 정확히 바꾼다', () => {
   const input = '2025.05.25 13:45';
-  const result = new Date('2025-05-25T13:45:00');
+  const result = new Date(2025, 4, 25, 13, 45);
   expect(parseRecruitmentDateString(input)).toEqual(result);
 });

 it('자정 시간 "YYYY.MM.DD 00:00" 형식을 올바르게 Date 객체로 변환한다', () => {
   const input = '2025.05.25 00:00';
-  const result = new Date('2025-05-25T00:00:00');
+  const result = new Date(2025, 4, 25, 0, 0);
   expect(parseRecruitmentDateString(input)).toEqual(result);
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const result = new Date('2025-05-25T13:45:00');
expect(parseRecruitmentDateString(input)).toEqual(result);
it('날짜와 시간이 포함된 문자열을 Date 객체로 정확히 바꾼다', () => {
const input = '2025.05.25 13:45';
- const result = new Date('2025-05-25T13:45:00');
+ const result = new Date(2025, 4, 25, 13, 45);
expect(parseRecruitmentDateString(input)).toEqual(result);
});
it('자정 시간 "YYYY.MM.DD 00:00" 형식을 올바르게 Date 객체로 변환한다', () => {
const input = '2025.05.25 00:00';
- const result = new Date('2025-05-25T00:00:00');
+ const result = new Date(2025, 4, 25, 0, 0);
expect(parseRecruitmentDateString(input)).toEqual(result);
});
🤖 Prompt for AI Agents
In frontend/src/utils/recruitmentPeriodParser.test.ts around lines 5 to 7 and 11
to 13, the test creates Date objects using ISO strings which are interpreted as
UTC, causing timezone-dependent failures. Replace these Date constructions with
numeric arguments (year, month, day, hour, minute, second) to create Date
objects in the local timezone and remove timezone dependency from the tests.

});

it('자정 시간 "YYYY.MM.DD 00:00" 형식을 올바르게 Date 객체로 변환한다', () => {
const input = '2025.05.25 00:00';
const result = new Date('2025-05-25T00:00:00');
expect(parseRecruitmentDateString(input)).toEqual(result);
});

it('공백이 없는 문자열이라면 예외가 발생한다.', () => {
const input = '2025.05.2513:45';
expect(() => parseRecruitmentDateString(input)).toThrow(
'유효하지 않은 날짜 형식입니다. 형식은 "YYYY.MM.DD HH:mm" 이어야 합니다.',
);
});

it('시간 부분이 누락된 경우 예외가 발생한다', () => {
const input = '2025.05.25 ';
expect(() => parseRecruitmentDateString(input)).toThrow(
'유효하지 않은 날짜 형식입니다. 형식은 "YYYY.MM.DD HH:mm" 이어야 합니다.',
);
});

it('날짜 부분이 누락된 경우 예외가 발생한다', () => {
const input = ' 13:45';
expect(() => parseRecruitmentDateString(input)).toThrow(
'유효하지 않은 날짜 형식입니다. 형식은 "YYYY.MM.DD HH:mm" 이어야 합니다.',
);
});

it('빈 문자열이 주어지면 예외가 발생한다', () => {
const input = '';
expect(() => parseRecruitmentDateString(input)).toThrow(
'유효하지 않은 날짜 형식입니다. 형식은 "YYYY.MM.DD HH:mm" 이어야 합니다.',
);
});

it('YYYY.MM.DD HH:mm 형식이 아닌 입력에 대해 에러를 던진다', () => {
const input = '1.1.1 1:1';
expect(() => parseRecruitmentDateString(input)).toThrow(
'유효하지 않은 날짜 형식입니다. 형식은 "YYYY.MM.DD HH:mm" 이어야 합니다.',
);
});
});
31 changes: 31 additions & 0 deletions frontend/src/utils/recruitmentPeriodParser.ts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { parse, isValid } from 'date-fns';
Copy link
Copy Markdown
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

파일명의 확장자를 확인해주세요.

파일명이 recruitmentPeriodParser.ts.ts로 되어 있는데, .ts.ts는 잘못된 확장자입니다. .ts만 사용해야 합니다.

다음 스크립트로 파일명을 확인해보겠습니다:


🏁 Script executed:

#!/bin/bash
# Description: 중복된 .ts 확장자를 가진 파일 확인

# Test: .ts.ts 확장자를 가진 파일 검색
fd "\.ts\.ts$" frontend/src/

Length of output: 79


파일명 확장자 중복 제거 요청

.ts.ts로 잘못 설정된 파일명을 단일 .ts 확장자로 변경해주세요.

  • 수정 대상
    • frontend/src/utils/recruitmentPeriodParser.ts.ts
      → frontend/src/utils/recruitmentPeriodParser.ts
  • 변경 후 해당 모듈을 import 하는 경로도 모두 .ts 확장자로 업데이트되었는지 검토 바랍니다.
- frontend/src/utils/recruitmentPeriodParser.ts.ts
+ frontend/src/utils/recruitmentPeriodParser.ts
🤖 Prompt for AI Agents
In frontend/src/utils/recruitmentPeriodParser.ts.ts at line 1, the file
extension is mistakenly duplicated as .ts.ts. Rename the file to have a single
.ts extension, changing it to frontend/src/utils/recruitmentPeriodParser.ts.
After renaming, update all import statements throughout the codebase that
reference this module to use the corrected .ts extension path.


export const parseRecruitmentDateString = (s: string): Date => {
const regex = /^\d{4}\.\d{2}\.\d{2} \d{2}:\d{2}$/;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

정규식 패턴을 명명된 상수로 추출해야 합니다.

코딩 가이드라인에 따라 매직 넘버와 문자열을 명명된 상수로 교체해야 합니다. 정규식 패턴을 상수로 추출하면 가독성과 재사용성이 향상됩니다.

다음과 같이 수정해주세요:

+const DATE_TIME_REGEX = /^\d{4}\.\d{2}\.\d{2} \d{2}:\d{2}$/;
+
 export const parseRecruitmentDateString = (s: string): Date => {
-  const regex = /^\d{4}\.\d{2}\.\d{2} \d{2}:\d{2}$/;
-  if (!regex.test(s)) {
+  if (!DATE_TIME_REGEX.test(s)) {
🤖 Prompt for AI Agents
In frontend/src/utils/recruitmentPeriodParser.ts.ts at line 4, the regex pattern
is currently a magic string. Extract this regex pattern into a named constant at
the top of the file to improve readability and reusability. Replace the inline
regex with this constant in the code.

if (!regex.test(s)) {
throw new Error(
'유효하지 않은 날짜 형식입니다. 형식은 "YYYY.MM.DD HH:mm" 이어야 합니다.',
);
Comment on lines +6 to +8
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

중복된 에러 메시지를 상수로 추출해야 합니다.

동일한 에러 메시지가 두 곳에서 반복되고 있습니다. DRY 원칙에 따라 상수로 추출하는 것이 좋습니다.

다음과 같이 수정해주세요:

+const INVALID_DATE_FORMAT_ERROR = '유효하지 않은 날짜 형식입니다. 형식은 "YYYY.MM.DD HH:mm" 이어야 합니다.';
+
 export const parseRecruitmentDateString = (s: string): Date => {
   const regex = /^\d{4}\.\d{2}\.\d{2} \d{2}:\d{2}$/;
   if (!regex.test(s)) {
-    throw new Error(
-      '유효하지 않은 날짜 형식입니다. 형식은 "YYYY.MM.DD HH:mm" 이어야 합니다.',
-    );
+    throw new Error(INVALID_DATE_FORMAT_ERROR);
   }
   const date = parse(s, 'yyyy.MM.dd HH:mm', new Date());
   if (!isValid(date)) {
-    throw new Error(
-      '유효하지 않은 날짜 형식입니다. 형식은 "YYYY.MM.DD HH:mm" 이어야 합니다.',
-    );
+    throw new Error(INVALID_DATE_FORMAT_ERROR);
   }

Also applies to: 12-14

🤖 Prompt for AI Agents
In frontend/src/utils/recruitmentPeriodParser.ts.ts around lines 6 to 8 and also
lines 12 to 14, the error message string '유효하지 않은 날짜 형식입니다. 형식은 "YYYY.MM.DD
HH:mm" 이어야 합니다.' is duplicated. To follow the DRY principle, extract this error
message into a constant at the top of the file and replace all occurrences of
the string with this constant.

}
const date = parse(s, 'yyyy.MM.dd HH:mm', new Date());
if (!isValid(date)) {
throw new Error(
'유효하지 않은 날짜 형식입니다. 형식은 "YYYY.MM.DD HH:mm" 이어야 합니다.',
);
}
return date;
};

export const parseRecruitmentPeriod = (
periodStr: string,
): { recruitmentStart: Date | null; recruitmentEnd: Date | null } => {
const parts = periodStr.split('~').map((s) => s.trim());
if (parts.length !== 2) {
return { recruitmentStart: null, recruitmentEnd: null };
}

return {
recruitmentStart: parseRecruitmentDateString(parts[0]),
recruitmentEnd: parseRecruitmentDateString(parts[1]),
};
};
20 changes: 0 additions & 20 deletions frontend/src/utils/stringToDate.ts

This file was deleted.