Skip to content

fix: [MOA-809] 홍보게시판 시작일 D-day 계산 버그 수정#1430

Open
lepitaaar wants to merge 3 commits intomainfrom
hotfix/promotion-dday-calculation
Open

fix: [MOA-809] 홍보게시판 시작일 D-day 계산 버그 수정#1430
lepitaaar wants to merge 3 commits intomainfrom
hotfix/promotion-dday-calculation

Conversation

@lepitaaar
Copy link
Copy Markdown
Contributor

@lepitaaar lepitaaar commented Apr 13, 2026

Closes #1427. getDday 함수에서 이벤트 시작일의 D-day 계산 버그를 수정하고, 관련 테스트 케이스를 보완했습니다.

Summary by CodeRabbit

릴리스 노트

  • 테스트

    • 한국어·전화번호 검증 로직의 테스트 커버리지 추가
    • D-Day 계산 경계값 테스트 케이스 강화
  • 버그 수정

    • D-Day 계산이 이제 정확하게 시간대를 무시하고 날짜 기준으로 처리
  • 잡무

    • 코드 정리: TODO 주석 제거
    • 테스트 환경 의존성 추가 및 업데이트

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 13, 2026

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

Project Deployment Actions Updated (UTC)
moadong Ready Ready Preview, Comment Apr 13, 2026 6:11am

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 13, 2026

Warning

.coderabbit.yaml has a parsing error

The CodeRabbit configuration file in this repository has a parsing error and default settings were used instead. Please fix the error(s) in the configuration file. You can initialize chat with CodeRabbit to get help with the configuration file.

💥 Parsing errors (1)
Validation error: Invalid regex pattern for base branch. Received: "**" at "reviews.auto_review.base_branches[0]"
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Walkthrough

이 PR은 홍보게시판 D-day 계산 버그를 수정하고, 백엔드 검증자 클래스에 대한 테스트를 추가하며, 테스트 의존성을 추가합니다. 프론트엔드의 상태 관리를 개선하고 불필요한 로깅을 제거합니다.

Changes

Cohort / File(s) Summary
테스트 의존성 추가
backend/build.gradle
H2 데이터베이스 및 Flapdoodle MongoDB 임베디드 테스트 의존성 2개 추가
검증자 클래스 정리
backend/src/main/java/moadong/global/validator/KoreanValidator.java, backend/src/main/java/moadong/global/validator/PhoneNumberValidator.java
각 클래스에서 TODO 주석 제거 (테스트 코드 작성 완료)
검증자 단위 테스트 추가
backend/src/test/java/moadong/unit/global/validator/KoreanValidatorTest.java, backend/src/test/java/moadong/unit/global/validator/PhoneNumberValidatorTest.java
KoreanValidator 및 PhoneNumberValidator의 정상 케이스(null, 빈 문자열) 및 매개변수화된 유효성/무효성 검사 테스트 추가
D-day 계산 버그 수정
frontend/src/pages/PromotionPage/utils/getDday.ts, frontend/src/pages/PromotionPage/utils/getDday.test.ts
시작일을 자정 기준으로 정규화하여 시작 당일이 D-1로 표시되는 버그 수정, 경계값 테스트 케이스 3개 추가
상태 관리 개선
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsTab.tsx
useApplicantSSE 훅 도입으로 컨텍스트 기반 applicants 상태 관리를 SSE 기반으로 전환
에러 로깅 정리
frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsx
catch 블록에서 console.error 로깅 제거 (사용자 alert는 유지)
스토리북 정리
frontend/src/pages/MainPage/components/StatusRadioButton/StatusRadioButton.stories.tsx
StatusRadioButton 스토리에서 디버그용 console.log 제거

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

🚀 hotfix, 🐞 Bug, 🛠 Fix, ✅ Test, 💻 FE

Suggested reviewers

  • seongwon030
  • suhyun113
  • oesnuj
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning 일부 변경사항이 범위를 벗어났습니다: 불필요한 console.error 제거, TODO 주석 제거, SSE 훅 도입 등이 이슈 #1427의 주요 목표와 무관한 추가 변경입니다. PR을 두 개로 분리하거나, 범위 밖의 변경사항(console.error 제거, TODO 주석 제거, SSE 훅 변경)을 별도 이슈로 추적하고 제거할 것을 권장합니다.
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 (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목은 MOA-809 홍보게시판 D-day 계산 버그 수정으로, 주요 변경사항인 getDday 함수의 버그 수정을 명확히 요약하고 있습니다.
Linked Issues check ✅ Passed PR의 모든 변경사항이 연결된 이슈 #1427의 요구사항을 충족합니다: getDday 함수를 날짜 단위 비교로 수정했고, getDday.test.ts의 테스트 케이스를 보완했으며, develop-fe 반영을 위한 준비가 완료되었습니다.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch hotfix/promotion-dday-calculation

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.

@github-actions
Copy link
Copy Markdown

✅ UI 변경사항 없음

구분 링크
📖 Storybook https://67904e61c16daa99a63b44a7-qbzliykibs.chromatic.com/

전체 56개 스토리 · 22개 컴포넌트

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

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

⚠️ Outside diff range comments (3)
frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsx (1)

93-96: ⚠️ Potential issue | 🟡 Minor

Line 93의 catch (e) 미사용 파라미터를 제거하세요.

현재 e는 사용되지 않으며, 프로젝트의 ESLint 규칙(@typescript-eslint/no-unused-vars)에 따라 경고가 발생합니다. Line 60과 동일하게 catch {}로 통일하는 것이 깔끔합니다.

✏️ 제안 diff
-    } catch (e) {
+    } catch {
       setApplicationOptions([]);
       setIsApplicationModalOpen(true);
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsx`
around lines 93 - 96, Remove the unused catch parameter in the ClubApplyButton
component's try/catch (replace "catch (e)" with "catch") so it matches the
project's ESLint rule and the existing pattern in the file; update the catch
that surrounds the async call which calls setApplicationOptions and
setIsApplicationModalOpen to use a parameterless catch block.
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsTab.tsx (2)

1-1: ⚠️ Potential issue | 🟡 Minor

Prettier 포맷팅 오류를 수정하세요.

파이프라인에서 포맷팅 이슈가 보고되었습니다. 다음 명령어를 실행하세요:

npx prettier --write "src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsTab.tsx"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsTab.tsx` at line 1,
Prettier formatting failed for ApplicantsTab.tsx; run the project's Prettier
formatter against the file (e.g., npx prettier --write
"src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsTab.tsx") or apply the
formatter in your editor to fix import/order/spacing issues shown around the
import line and ensure the ApplicantsTab component file is saved with
Prettier-compliant formatting.

64-68: ⚠️ Potential issue | 🔴 Critical

setApplicationFormId가 정의되지 않았습니다.

setApplicationFormId가 이 useEffect에서 사용되지만, 더 이상 useAdminClubContext()에서 추출되지 않습니다. 이로 인해 ReferenceError가 발생합니다.

AI 요약에 따르면, SSE 연결이 이제 useApplicantSSE 훅 내부에서 관리되므로 이 useEffect는 더 이상 필요하지 않을 수 있습니다. Context snippet에서 AdminClubContext가 이미 SSE 연결을 내부적으로 처리하고 있음을 확인할 수 있습니다.

🐛 불필요한 useEffect 제거 또는 setApplicationFormId 복원

Option 1: SSE가 훅에서 처리된다면 이 useEffect 제거

-  // SSE 연결 활성화
-  useEffect(() => {
-    setApplicationFormId(applicationFormId ?? null);
-    return () => setApplicationFormId(null);
-  }, [applicationFormId, setApplicationFormId]);

Option 2: Context에서 여전히 필요하다면 setApplicationFormId 추출

-  const { clubId } = useAdminClubContext();
+  const { clubId, setApplicationFormId } = useAdminClubContext();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsTab.tsx` around
lines 64 - 68, The useEffect in ApplicantsTab.tsx references
setApplicationFormId which is no longer provided by useAdminClubContext, causing
a ReferenceError; either remove this entire useEffect (preferred if SSE is now
managed by useApplicantSSE) or restore setApplicationFormId by extracting it
from useAdminClubContext so the effect can safely call
setApplicationFormId(applicationFormId ?? null) and cleanup; locate the effect
in ApplicantsTab.tsx (look for useEffect that sets applicationFormId) and
implement one of the two options, ensuring no dangling references remain and
imports/hooks (useApplicantSSE, useAdminClubContext) reflect the chosen
approach.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@backend/src/test/java/moadong/unit/global/validator/KoreanValidatorTest.java`:
- Line 13: The test class KoreanValidatorTest is missing the `@UnitTest`
annotation so it isn't picked up by the unitTest Gradle task; add the `@UnitTest`
annotation to the KoreanValidatorTest class declaration and include the
corresponding import for the UnitTest annotation so the test is included by the
backend build's includeTags 'UnitTest' filtering.

In
`@backend/src/test/java/moadong/unit/global/validator/PhoneNumberValidatorTest.java`:
- Around line 42-46: The test currently expects "050-1234-5678" and
"070-1234-5678" to be invalid, but PhoneNumberValidator's regex branch (the
pattern using "0\\d{1,2}") permits those prefixes; either update the validator
regex in PhoneNumberValidator (adjust the prefix pattern to explicitly exclude
050 and 070 or match only allowed prefixes per policy) or change the
PhoneNumberValidatorTest ValueSource to expect valid (assertTrue) for the "050"
and "070" cases so tests reflect the validator behavior—locate the regex in
PhoneNumberValidator and the ValueSource list in PhoneNumberValidatorTest to
apply the chosen fix.
- Line 13: The test class PhoneNumberValidatorTest is missing the `@UnitTest`
annotation so it will be skipped by the unitTest task; add the `@UnitTest`
annotation to the PhoneNumberValidatorTest class declaration (and add the
corresponding import for `@UnitTest`) so the class is picked up by includeTags
'UnitTest' during test execution.

In `@frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsTab.tsx`:
- Around line 26-28: 현재 파일에서 applicationFormId를 useParams에서 추출하지 않았고 존재하지 않는 훅
useApplicantSSE를 사용하고 있으므로, useParams로 applicationFormId를 가져오고
useAdminClubContext에서 applicantsData 및 setApplicantsData 같은 필요한 상태와 셋터를 직접 받아와
useApplicantSSE 호출을 제거하세요; 구체적으로 applicationFormId는 useParams()로 추출하고
useAdminClubContext()에서 applicantsData, setApplicantsData(및 필요 시 다른 관련 상태)를 구조분해
할당하도록 변경해 파일 내 useApplicantSSE 참조를 모두 대체하세요.

In `@frontend/src/pages/PromotionPage/utils/getDday.ts`:
- Around line 2-13: The D-day calculation normalizes dates in local time using
setHours, causing timezone-dependent errors; update the normalization to use UTC
by replacing now.setHours(0,0,0,0), startDate.setHours(0,0,0,0), and
endDate.setHours(0,0,0,0) with now.setUTCHours(0,0,0,0),
startDate.setUTCHours(0,0,0,0), and endDate.setUTCHours(0,0,0,0) respectively in
getDday (variables now, startDate, endDate) so eventStartDate/eventEndDate (UTC
strings) are normalized consistently in UTC before using getTime().

---

Outside diff comments:
In `@frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsTab.tsx`:
- Line 1: Prettier formatting failed for ApplicantsTab.tsx; run the project's
Prettier formatter against the file (e.g., npx prettier --write
"src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsTab.tsx") or apply the
formatter in your editor to fix import/order/spacing issues shown around the
import line and ensure the ApplicantsTab component file is saved with
Prettier-compliant formatting.
- Around line 64-68: The useEffect in ApplicantsTab.tsx references
setApplicationFormId which is no longer provided by useAdminClubContext, causing
a ReferenceError; either remove this entire useEffect (preferred if SSE is now
managed by useApplicantSSE) or restore setApplicationFormId by extracting it
from useAdminClubContext so the effect can safely call
setApplicationFormId(applicationFormId ?? null) and cleanup; locate the effect
in ApplicantsTab.tsx (look for useEffect that sets applicationFormId) and
implement one of the two options, ensuring no dangling references remain and
imports/hooks (useApplicantSSE, useAdminClubContext) reflect the chosen
approach.

In
`@frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsx`:
- Around line 93-96: Remove the unused catch parameter in the ClubApplyButton
component's try/catch (replace "catch (e)" with "catch") so it matches the
project's ESLint rule and the existing pattern in the file; update the catch
that surrounds the async call which calls setApplicationOptions and
setIsApplicationModalOpen to use a parameterless catch block.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5683c88f-93e6-4784-899f-768ade93398a

📥 Commits

Reviewing files that changed from the base of the PR and between 83cb37b and b8daf7a.

📒 Files selected for processing (10)
  • backend/build.gradle
  • backend/src/main/java/moadong/global/validator/KoreanValidator.java
  • backend/src/main/java/moadong/global/validator/PhoneNumberValidator.java
  • backend/src/test/java/moadong/unit/global/validator/KoreanValidatorTest.java
  • backend/src/test/java/moadong/unit/global/validator/PhoneNumberValidatorTest.java
  • frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsTab.tsx
  • frontend/src/pages/ClubDetailPage/components/ClubApplyButton/ClubApplyButton.tsx
  • frontend/src/pages/MainPage/components/StatusRadioButton/StatusRadioButton.stories.tsx
  • frontend/src/pages/PromotionPage/utils/getDday.test.ts
  • frontend/src/pages/PromotionPage/utils/getDday.ts
💤 Files with no reviewable changes (3)
  • backend/src/main/java/moadong/global/validator/KoreanValidator.java
  • backend/src/main/java/moadong/global/validator/PhoneNumberValidator.java
  • frontend/src/pages/MainPage/components/StatusRadioButton/StatusRadioButton.stories.tsx

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

class KoreanValidatorTest {
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 | 🟠 Major

@UnitTest 태그를 추가해 unitTest 태스크에 포함되도록 해주세요.

현재 클래스에 태그가 없어 backend/build.gradleincludeTags 'UnitTest' 조건 실행에서 누락됩니다.

As per coding guidelines "backend//src/test/java//*Test.java: Annotate unit tests with @UnitTest and integration tests with @IntegrationTest".

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

In `@backend/src/test/java/moadong/unit/global/validator/KoreanValidatorTest.java`
at line 13, The test class KoreanValidatorTest is missing the `@UnitTest`
annotation so it isn't picked up by the unitTest Gradle task; add the `@UnitTest`
annotation to the KoreanValidatorTest class declaration and include the
corresponding import for the UnitTest annotation so the test is included by the
backend build's includeTags 'UnitTest' filtering.

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

class PhoneNumberValidatorTest {
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 | 🟠 Major

이 테스트 클래스에도 @UnitTest 태그가 필요합니다.

태그가 없으면 unitTest 태스크(includeTags 'UnitTest')에서 실행되지 않습니다.

As per coding guidelines "backend//src/test/java//*Test.java: Annotate unit tests with @UnitTest and integration tests with @IntegrationTest".

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

In
`@backend/src/test/java/moadong/unit/global/validator/PhoneNumberValidatorTest.java`
at line 13, The test class PhoneNumberValidatorTest is missing the `@UnitTest`
annotation so it will be skipped by the unitTest task; add the `@UnitTest`
annotation to the PhoneNumberValidatorTest class declaration (and add the
corresponding import for `@UnitTest`) so the class is picked up by includeTags
'UnitTest' during test execution.

Comment on lines +42 to +46
@ValueSource(strings = {
"010-123-456", "010-12345-678",
"abc-defg-hijk", "010-1234-567a",
"050-1234-5678", "070-1234-5678"
})
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 | 🟠 Major

050/070 케이스는 현재 검증기 구현과 충돌합니다.

backend/src/main/java/moadong/global/validator/PhoneNumberValidator.java의 정규식 분기(0\\d{1,2})는 050/070을 허용하므로, 여기서 assertFalse를 기대하면 테스트 실패 가능성이 큽니다. 정책에 맞게 검증기 정규식 또는 테스트 기대값 중 하나를 일치시켜 주세요.

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

In
`@backend/src/test/java/moadong/unit/global/validator/PhoneNumberValidatorTest.java`
around lines 42 - 46, The test currently expects "050-1234-5678" and
"070-1234-5678" to be invalid, but PhoneNumberValidator's regex branch (the
pattern using "0\\d{1,2}") permits those prefixes; either update the validator
regex in PhoneNumberValidator (adjust the prefix pattern to explicitly exclude
050 and 070 or match only allowed prefixes per policy) or change the
PhoneNumberValidatorTest ValueSource to expect valid (assertTrue) for the "050"
and "070" cases so tests reflect the validator behavior—locate the regex in
PhoneNumberValidator and the ValueSource list in PhoneNumberValidatorTest to
apply the chosen fix.

Comment on lines +26 to +28
const { clubId } = useAdminClubContext();
const { applicantsData, setApplicantsData } =
useApplicantSSE(applicationFormId);
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 | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: useApplicantSSE 훅 파일 위치 검색
fd -t f -i 'useApplicantSSE' --extension ts --extension tsx

Repository: Moadong/moadong

Length of output: 41


🏁 Script executed:

cat -n frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsTab.tsx | head -50

Repository: Moadong/moadong

Length of output: 2287


🏁 Script executed:

fd -type f -path "*/frontend/src/hooks/*" \( -name "*.ts" -o -name "*.tsx" \) | head -20

Repository: Moadong/moadong

Length of output: 229


🏁 Script executed:

fd -type f -path "*/frontend/src/hooks/Queries/*" \( -name "*.ts" -o -name "*.tsx" \)

Repository: Moadong/moadong

Length of output: 229


🏁 Script executed:

rg "useApplicantSSE" --type ts --type tsx

Repository: Moadong/moadong

Length of output: 86


🏁 Script executed:

rg "applicationFormId" --type-add 'vue:*.vue' --type-add 'custom:*.{ts,tsx}' -g 'frontend/**' -A 2 -B 2

Repository: Moadong/moadong

Length of output: 35056


🏁 Script executed:

fd -t f -path "*/frontend/src/hooks/*" | head -30

Repository: Moadong/moadong

Length of output: 227


🏁 Script executed:

rg "SSE|useApplicant" -g 'frontend/**' --max-count 20

Repository: Moadong/moadong

Length of output: 1908


🏁 Script executed:

cat -n frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsTab.tsx | sed -n '1,100p'

Repository: Moadong/moadong

Length of output: 4264


applicationFormIduseParams에서 추출하고, 컨텍스트에서 필요한 상태를 모두 가져와야 합니다.

useApplicantSSE는 존재하지 않으며, 필요한 상태와 setter들이 AdminClubContext에서 제공됩니다:

 const ApplicantsTab = () => {
-  const { clubId } = useAdminClubContext();
-  const { applicantsData, setApplicantsData } =
-    useApplicantSSE(applicationFormId);
+  const { applicationFormId } = useParams<{ applicationFormId: string }>();
+  const {
+    clubId,
+    applicantsData,
+    setApplicantsData,
+    setApplicationFormId,
+  } = useAdminClubContext();
   const navigate = useNavigate();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsTab.tsx` around
lines 26 - 28, 현재 파일에서 applicationFormId를 useParams에서 추출하지 않았고 존재하지 않는 훅
useApplicantSSE를 사용하고 있으므로, useParams로 applicationFormId를 가져오고
useAdminClubContext에서 applicantsData 및 setApplicantsData 같은 필요한 상태와 셋터를 직접 받아와
useApplicantSSE 호출을 제거하세요; 구체적으로 applicationFormId는 useParams()로 추출하고
useAdminClubContext()에서 applicantsData, setApplicantsData(및 필요 시 다른 관련 상태)를 구조분해
할당하도록 변경해 파일 내 useApplicantSSE 참조를 모두 대체하세요.

Comment on lines +2 to +13
const now = new Date();
now.setHours(0, 0, 0, 0);

const startDate = new Date(eventStartDate);
startDate.setHours(0, 0, 0, 0);

const endDate = new Date(eventEndDate);
endDate.setHours(0, 0, 0, 0);

const currentTime = now.getTime();
const eventStartTime = startDate.getTime();
const eventEndTime = endDate.getTime();
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 | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# 이벤트 날짜 필드의 실제 포맷(UTC Z/offset 포함 여부) 확인
rg -n -C2 '\beventStartDate\b|\beventEndDate\b'

Repository: Moadong/moadong

Length of output: 25473


🏁 Script executed:

# Check the getDday test file
fd -n getDday.test.ts --type f

Repository: Moadong/moadong

Length of output: 289


🏁 Script executed:

# Read the getDday test file to see what formats are tested
cat -n frontend/src/pages/PromotionPage/utils/getDday.test.ts 2>/dev/null || echo "File not found"

Repository: Moadong/moadong

Length of output: 2434


🏁 Script executed:

# Also check the actual function implementation
cat -n frontend/src/pages/PromotionPage/utils/getDday.ts

Repository: Moadong/moadong

Length of output: 1021


setHours 대신 setUTCHours 사용 필요 - UTC 타임스탬프 처리 오류

백엔드에서 전송하는 eventStartDateeventEndDate는 UTC 형식(...Z)이지만, 현재 코드는 setHours()로 정규화하고 있습니다. 이는 로컬 시간대 기준으로 작동하므로, 사용자 시스템의 타임존에 따라 D-day 계산 결과가 달라질 수 있습니다. 예를 들어 KST(UTC+9) 환경에서는 UTC 기준 2026-03-25 00:00:00Z가 로컬 시간 2026-03-25 09:00:00으로 파싱된 후, setHours(0, 0, 0, 0)으로 정규화되면서 실제로는 2026-03-24 15:00:00 UTC가 됩니다.

수정 제안
 export const getDDay = (eventStartDate: string, eventEndDate: string) => {
   const now = new Date();
-  now.setHours(0, 0, 0, 0);
+  now.setUTCHours(0, 0, 0, 0);

   const startDate = new Date(eventStartDate);
-  startDate.setHours(0, 0, 0, 0);
+  startDate.setUTCHours(0, 0, 0, 0);

   const endDate = new Date(eventEndDate);
-  endDate.setHours(0, 0, 0, 0);
+  endDate.setUTCHours(0, 0, 0, 0);
📝 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 now = new Date();
now.setHours(0, 0, 0, 0);
const startDate = new Date(eventStartDate);
startDate.setHours(0, 0, 0, 0);
const endDate = new Date(eventEndDate);
endDate.setHours(0, 0, 0, 0);
const currentTime = now.getTime();
const eventStartTime = startDate.getTime();
const eventEndTime = endDate.getTime();
const now = new Date();
now.setUTCHours(0, 0, 0, 0);
const startDate = new Date(eventStartDate);
startDate.setUTCHours(0, 0, 0, 0);
const endDate = new Date(eventEndDate);
endDate.setUTCHours(0, 0, 0, 0);
const currentTime = now.getTime();
const eventStartTime = startDate.getTime();
const eventEndTime = endDate.getTime();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/pages/PromotionPage/utils/getDday.ts` around lines 2 - 13, The
D-day calculation normalizes dates in local time using setHours, causing
timezone-dependent errors; update the normalization to use UTC by replacing
now.setHours(0,0,0,0), startDate.setHours(0,0,0,0), and
endDate.setHours(0,0,0,0) with now.setUTCHours(0,0,0,0),
startDate.setUTCHours(0,0,0,0), and endDate.setUTCHours(0,0,0,0) respectively in
getDday (variables now, startDate, endDate) so eventStartDate/eventEndDate (UTC
strings) are normalized consistently in UTC before using getTime().

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.

[hotfix] MOA-809 홍보게시판 D-day 시작일 당일이 D-1로 표시되는 버그를 수정한다

1 participant