Skip to content

fix: 신고 API 백엔드 개편 대응 (POST /reports, targetType/reason) - #404

Merged
yhi9839 merged 11 commits into
mainfrom
fix-403-report
Jun 25, 2026
Merged

yhi9839 merged 11 commits into
mainfrom
fix-403-report

Conversation

@yhi9839

@yhi9839 yhi9839 commented Jun 22, 2026 •

Copy link
Copy Markdown
Contributor

📌 개요 (Summary)

  • 백엔드 신고 API가 전면 개편되어(POST /members/report → POST /reports, 요청 구조 변경) 프론트엔드 신고하기가 동작하지 않던 문제를 수정합니다.
  • Swagger(/v3/api-docs) 및 BE 소스로 신규 스펙 교차 확인 후 반영했습니다.
  • 관련 이슈: fix: 신고/차단 기능 수정 #403

🛠 변경 사항 (Changes)

  • 새로운 기능 추가
  • 버그 수정
  • 코드 리팩토링
  • 문서 업데이트
  • 기타 (설명: )

상세

  1. 엔드포인트 변경 — 생성 /reports, 내 신고 목록 /reports/me
  2. 요청 구조 교체 — { reportedMemberNickname, reportType } → { targetType, targetId, reason, content }
    • reason(사유): GENERAL / INSULT / INAPPROPRIATE_CONTENT / SPAM
    • targetType: MEMBER / BOOK_STORY / BOOK_STORY_COMMENT / CLUB_NOTICE_COMMENT / CLUB_TOPIC / CLUB_BOOK_REVIEW 등
  3. ReportModal — 선택지를 카테고리 → 신고 사유로 변경, onSubmit(reason, content)
  4. 호출부 7곳 — 화면별 targetType/targetId 주입 (프로필=MEMBER, 댓글=*_COMMENT, 발제/한줄평=CLUB_TOPIC/CLUB_BOOK_REVIEW), 기존 mapReportTypeToApi 제거
  5. 내 신고 목록 — 응답 필드 remap (reasonDescription / displayName / displayImageUrl / reportedAt)
  6. 차단 확인 모달 — 버튼 위치 변경 (취소 좌측 / 차단 우측)

⚠️ 어드민 신고 목록 뷰(Admin/users/ReportList)는 별도 admin API를 사용하여 이번 범위에서 제외했습니다.

📸 스크린샷 (Screenshots)

(신고 모달 사유 선택 / 차단 모달 버튼 위치 — 필요 시 첨부)

✅ 체크리스트 (Checklist)

  • 빌드가 성공적으로 수행되었나요? (pnpm build)
  • 린트 에러가 없나요? (pnpm lint) — ⚠️ 저장소 사전 존재 에러 있음, 본 PR 변경분은 신규 에러 없음
  • 불필요한 콘솔 로그나 주석을 제거했나요?

Summary by CodeRabbit

  • New Features
    • Updated the reporting experience to use structured “reason + target” submissions across book stories, comments, notices, club topics, reviews, and profiles.
    • Report modal now defaults to “GENERAL” and submits with the selected reason.
  • Bug Fixes
    • Improved block confirmation dialog by reordering actions for clearer cancellation/blocking.
  • Improvements
    • Refreshed “My Reports” history display to show updated reason text, content, images, and consistent dates.
    • Refined comment reporting to target the correct comment and include reason-based details.
    • Home recommendation section is now consistently rendered with improved responsive layout.

yhi9839 and others added 2 commits June 22, 2026 08:59
- 신고 생성/목록 엔드포인트 변경 (/members/report→/reports, /reports/me)
- 요청 구조 변경: reportType → targetType + targetId + reason
- ReportModal: 선택지를 신고 사유(GENERAL/INSULT/INAPPROPRIATE_CONTENT/SPAM)로 변경
- 호출부별 targetType 주입 (MEMBER/BOOK_STORY(_COMMENT)/CLUB_NOTICE_COMMENT/CLUB_TOPIC/CLUB_BOOK_REVIEW)
- 내 신고 목록 응답 필드 remap (displayName/displayImageUrl/reasonDescription)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@yhi9839
yhi9839 requested a review from shinwokkang June 22, 2026 00:35
@yhi9839 yhi9839 linked an issue Jun 22, 2026 that may be closed by this pull request
4 tasks
@vercel

vercel Bot commented Jun 22, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
checkmo Ready Ready Preview, Comment Jun 24, 2026 1:04pm

@coderabbitai

coderabbitai Bot commented Jun 22, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR updates the reporting flow to use ReportReason and targetType/targetId throughout types, services, hooks, modal UI, and consumer screens. It also changes report history rendering and adjusts several home, search, and page layout components.

Changes

Report Contract Refactor

Layer / File(s) Summary
Types, constants, and endpoints
src/types/report.ts, src/types/member.ts, src/constants/report.ts, src/lib/api/endpoints/member.ts
Adds the new report request and response types, removes the old member report types, replaces the report type map with reason labels, and moves report endpoints to /reports paths.
Service and mutation wiring
src/services/reportService.ts, src/services/memberService.ts, src/hooks/mutations/useMemberMutations.ts, src/hooks/mutations/useReportMemberMutations.ts, src/hooks/useReportBlockFlow.ts
Re-types report submission and report-history service calls, and updates mutation/report-block callbacks to accept ReportReason.
Report modal and block confirm UI
src/components/common/modals/report-block/ReportModal.tsx, src/components/common/modals/report-block/BlockConfirmModal.tsx
ReportModal now selects report reasons and submits (reason, content), and BlockConfirmModal swaps the button order.
Consumer reporting flows and history view
src/components/base-ui/Profile/OtherUser/ProfileUserInfo.tsx, src/components/base-ui/Admin/stories/bookstory_detail.tsx, src/components/base-ui/Admin/stories/comment_section.tsx, src/components/base-ui/BookStory/Detatil/bookstory_detail.tsx, src/components/base-ui/Comment/comment_section_bookcase.tsx, src/components/base-ui/Comment/comment_section_notice.tsx, src/app/(main)/groups/[id]/bookcase/[bookId]/BookDetailPageClient.tsx, src/app/(main)/setting/report/ReportPageClient.tsx
Reporting call sites now use targetType, targetId, and ReportReason, and the report history page renders the updated report fields.

Home and layout adjustments

Layer / File(s) Summary
Home recommendation rendering
src/app/(main)/home/HomePageClient.tsx, src/components/base-ui/home/Recommendation/HomeRecommendationSection.tsx, src/components/base-ui/home/Recommendation/list_subscribe_large.tsx
The recommendation section now hides when empty, uses a single list path, and supports responsive widths and optional title hiding.
Home club section and search card
src/components/base-ui/Group-Search/search_mybookclub.tsx, src/components/base-ui/home/Club/HomeClubSection.tsx
Mybookclub accepts footer and single-column options, and HomeClubSection always renders it with footer actions for group search and creation.
Page spacing and modal buttons
src/app/(main)/news/[id]/NewsDetailClient.tsx, src/components/common/modals/report-block/BlockConfirmModal.tsx
The news detail wrapper padding changes at the t: breakpoint, and the block confirm buttons are reordered.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • checkmo2025/FE#302: Uses the same reporting UI and service areas, but this PR replaces the older report type contract with ReportReason and targetType/targetId.

Suggested labels

🐛 bug

🐰 Hop hop, the report types changed their tune,
Reasons and targets now arrive by moon.
The home cards flex, the lists fall into place,
And every modal keeps a tidy little pace.
I nibble a carrot and bounce down the lane —
Structured reports, and layouts remain!

🚥 Pre-merge checks | ✅ 4 | ❌ 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 (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adapting the frontend report flow to the backend API overhaul with POST /reports and targetType/reason payloads.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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 fix-403-report

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.

@gemini-code-assist gemini-code-assist Bot left a comment

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.

Code Review

This pull request refactors the reporting system by replacing localized types and mappings with unified types (ReportReason, ReportTargetType, ReportRequest, etc.) and updating the corresponding API endpoints to /reports and /reports/me. It also updates various UI components to adapt to these changes. Feedback is provided regarding checking the API response success status in reportService.ts to prevent silent failures, and adding optional chaining to report.reportedAt in ReportPageClient.tsx to avoid potential runtime errors.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +7 to 14
reportMember: async (body: ReportRequest): Promise<number> => {
const res = await apiClient.post<ReportCreateResponse>(
MEMBER_ENDPOINTS.REPORT,
body
);

return res.result;
},

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.

high

apiClient.post 호출 후 응답의 성공 여부(res.isSuccess)를 확인하지 않고 바로 res.result를 반환하고 있습니다.

apiClient는 요청이 실패하더라도 자동으로 에러를 던지지 않고 isSuccess: false인 응답 객체를 반환하므로, 이 상태에서 에러를 명시적으로 던져주지 않으면 호출부(Mutation 및 UI)에서 실패를 성공으로 오인하여 "신고가 접수되었습니다."와 같은 잘못된 피드백을 노출하게 됩니다.

memberService와 동일하게 isSuccess 여부를 체크하여 에러를 던지도록 수정해야 합니다.

  reportMember: async (body: ReportRequest): Promise<number> => {
    const res = await apiClient.post<ReportCreateResponse>(
      MEMBER_ENDPOINTS.REPORT,
      body
    );

    if (!res.isSuccess) {
      throw new Error(res.message || "신고 접수에 실패했습니다.");
    }

    return res.result!;
  },

content={report.content}
date={report.reportDate.substring(0, 10).replace(/-/g, ".")}
profileImageUrl={report.reportedMemberProfileImageUrl}
date={report.reportedAt.substring(0, 10).replace(/-/g, ".")}

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.

medium

report.reportedAt 값에 대해 바로 substring 메서드를 호출하고 있습니다.

API 응답 데이터의 유효성 검증 및 방어적 프로그래밍(Defensive Programming) 관점에서, 만약 reportedAt 값이 누락되거나 null/undefined로 내려올 경우 런타임 에러(TypeError)가 발생하여 전체 페이지가 렌더링되지 않고 크래시될 위험이 있습니다.

옵셔널 체이닝(?.)과 기본값 처리를 적용하고, 더 현대적인 slice 메서드를 사용하여 안전하게 문자열을 처리하도록 개선하는 것을 권장합니다.

Suggested change
date={report.reportedAt.substring(0, 10).replace(/-/g, ".")}
date={report.reportedAt?.slice(0, 10).replace(/-/g, ".") ?? ""}

@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

🧹 Nitpick comments (2)
src/components/base-ui/Comment/comment_section_notice.tsx (1)

47-50: 🧹 Nitpick | 🔵 Trivial | 💤 Low value

Consider removing unused reportedMemberNickname from state.

The reportTarget state still includes reportedMemberNickname, but handleSubmitReport no longer uses it—only commentId is used for targetId. This is a minor cleanup opportunity.

♻️ Suggested cleanup
   const [reportTarget, setReportTarget] = useState<{
     commentId: number;
-    reportedMemberNickname: string;
   } | null>(null);

And update handleReportComment:

     setReportTarget({
       commentId: id,
-      reportedMemberNickname: target.authorName,
     });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/base-ui/Comment/comment_section_notice.tsx` around lines 47 -
50, The reportTarget state declaration includes an unused reportedMemberNickname
property that is never consumed by handleSubmitReport, which only uses commentId
for the targetId. Remove the reportedMemberNickname field from the state type
definition in the useState hook, and then update the handleReportComment
function to not set or pass this property when updating the reportTarget state.
src/components/common/modals/report-block/ReportModal.tsx (1)

34-44: 🧹 Nitpick | 🔵 Trivial

Extract form reset logic out of the event listener effect.

The effect at lines 34 and 37 calls setReason and setReportContent synchronously when isOpen changes, which triggers a second render and matches the react-hooks/set-state-in-effect rule. This is unnecessary—the effect should only manage the Escape listener lifecycle. Compare with similar modals like ActionSelectionModal.tsx and BlockConfirmModal.tsx in the same directory, which handle only the listener without state mutations.

Instead, reset form state when the modal closes by calling a dedicated function from the close handler:

+    const resetForm = () => {
+        setReason(defaultReason);
+        setReportContent("");
+    };
+
+    const handleClose = () => {
+        resetForm();
+        onClose();
+    };
+
     useEffect(() => {
         const handleEscape = (e: KeyboardEvent) => {
             if (e.key === "Escape" && isOpen) {
-                onClose();
+                handleClose();
             }
         };
 
         if (isOpen) {
             document.addEventListener("keydown", handleEscape);
-            setReason(defaultReason);
-        } else {
-            // Reset state when closed
-            setReason(defaultReason);
-            setReportContent("");
         }
 
         return () => {
             document.removeEventListener("keydown", handleEscape);
         };
-    }, [isOpen, onClose, defaultReason]);
+    }, [isOpen, handleClose]);

This eliminates the extra render and aligns the component with the modal patterns already established in your codebase.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/common/modals/report-block/ReportModal.tsx` around lines 34 -
44, Extract the form reset logic (setReason and setReportContent calls) out of
the current useEffect hook in ReportModal.tsx. Keep only the event listener
management (document.removeEventListener for the keydown handler and
handleEscape) in the effect. Create a separate cleanup function that calls both
setReason(defaultReason) and setReportContent("") and invoke this cleanup
function directly from the onClose handler instead of relying on the effect to
trigger the resets when isOpen changes. This ensures the effect only manages the
Escape listener lifecycle and eliminates the extra render caused by the state
mutations in the effect.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/services/memberService.ts`:
- Around line 134-136: The condition `if (cursorId)` in the cursorId parameter
append block uses a falsy check which incorrectly skips the value 0, breaking
pagination when 0 is a valid cursor. Replace the truthiness check with an
explicit undefined check (such as `if (cursorId !== undefined)` or `if (cursorId
!= null)`) to allow 0 as a valid cursor value while still excluding null and
undefined values.

In `@src/services/reportService.ts`:
- Around line 7-14: The reportMember method returns res.result unconditionally
without verifying that the API call was successful. Add a check for the
isSuccess property on the response object before returning res.result. If the
API response indicates failure (isSuccess is false), handle the error
appropriately by either throwing an error or returning a failure value instead
of propagating failed submissions as successful ones.

In `@src/types/report.ts`:
- Line 25: The documentation comment for the `content` field in the report.ts
file states a 500-character maximum limit, but the ReportModal component
enforces a 400-character limit, causing a mismatch between documented and actual
behavior. Update the comment on line 25 describing the `content` field to
specify the correct 400-character maximum limit to align with the UI validation
enforced in ReportModal.

---

Nitpick comments:
In `@src/components/base-ui/Comment/comment_section_notice.tsx`:
- Around line 47-50: The reportTarget state declaration includes an unused
reportedMemberNickname property that is never consumed by handleSubmitReport,
which only uses commentId for the targetId. Remove the reportedMemberNickname
field from the state type definition in the useState hook, and then update the
handleReportComment function to not set or pass this property when updating the
reportTarget state.

In `@src/components/common/modals/report-block/ReportModal.tsx`:
- Around line 34-44: Extract the form reset logic (setReason and
setReportContent calls) out of the current useEffect hook in ReportModal.tsx.
Keep only the event listener management (document.removeEventListener for the
keydown handler and handleEscape) in the effect. Create a separate cleanup
function that calls both setReason(defaultReason) and setReportContent("") and
invoke this cleanup function directly from the onClose handler instead of
relying on the effect to trigger the resets when isOpen changes. This ensures
the effect only manages the Escape listener lifecycle and eliminates the extra
render caused by the state mutations in the effect.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: abee463b-863b-4443-a913-b99505a5da66

📥 Commits

Reviewing files that changed from the base of the PR and between 7b7782e and ce5c28d.

📒 Files selected for processing (19)
  • src/app/(main)/groups/[id]/bookcase/[bookId]/BookDetailPageClient.tsx
  • src/app/(main)/setting/report/ReportPageClient.tsx
  • src/components/base-ui/Admin/stories/bookstory_detail.tsx
  • src/components/base-ui/Admin/stories/comment_section.tsx
  • src/components/base-ui/BookStory/Detatil/bookstory_detail.tsx
  • src/components/base-ui/Comment/comment_section_bookcase.tsx
  • src/components/base-ui/Comment/comment_section_notice.tsx
  • src/components/base-ui/Profile/OtherUser/ProfileUserInfo.tsx
  • src/components/common/modals/report-block/BlockConfirmModal.tsx
  • src/components/common/modals/report-block/ReportModal.tsx
  • src/constants/report.ts
  • src/hooks/mutations/useMemberMutations.ts
  • src/hooks/mutations/useReportMemberMutations.ts
  • src/hooks/useReportBlockFlow.ts
  • src/lib/api/endpoints/member.ts
  • src/services/memberService.ts
  • src/services/reportService.ts
  • src/types/member.ts
  • src/types/report.ts
💤 Files with no reviewable changes (1)
  • src/types/member.ts

Comment on lines 134 to 136
if (cursorId) {
params.append("cursorId", cursorId.toString());
}

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 | 🟡 Minor | ⚡ Quick win

Use an explicit undefined check for cursorId.

if (cursorId) skips 0, which can break pagination if 0 is a valid cursor.

Suggested fix
-        if (cursorId) {
+        if (cursorId !== undefined) {
             params.append("cursorId", cursorId.toString());
         }
📝 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
if (cursorId) {
params.append("cursorId", cursorId.toString());
}
if (cursorId !== undefined) {
params.append("cursorId", cursorId.toString());
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/services/memberService.ts` around lines 134 - 136, The condition `if
(cursorId)` in the cursorId parameter append block uses a falsy check which
incorrectly skips the value 0, breaking pagination when 0 is a valid cursor.
Replace the truthiness check with an explicit undefined check (such as `if
(cursorId !== undefined)` or `if (cursorId != null)`) to allow 0 as a valid
cursor value while still excluding null and undefined values.

Comment thread src/services/reportService.ts Resolved
Comment thread src/types/report.ts
/**
* 신고 생성 요청 (POST /reports)
* - targetId: MEMBER 이면 닉네임, 그 외에는 엔티티 ID 문자열
* - content: 선택 (최대 500자)

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 | 🟡 Minor | ⚡ Quick win

Align content max-length contract with UI validation.

Line 25 documents a 500-char limit, but ReportModal currently enforces 400 chars. This drift can block valid requests if backend accepts 500.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/types/report.ts` at line 25, The documentation comment for the `content`
field in the report.ts file states a 500-character maximum limit, but the
ReportModal component enforces a 400-character limit, causing a mismatch between
documented and actual behavior. Update the comment on line 25 describing the
`content` field to specify the correct 400-character maximum limit to align with
the UI validation enforced in ReportModal.

@yhi9839

yhi9839 commented Jun 22, 2026

Copy link
Copy Markdown
Contributor Author
  • 신고 로직 API 스펙에 맞게 변경
image - 차단하기 모달 버튼 위치 변경 image

apiClient.post 는 isSuccess:false 여도 throw 하지 않으므로,
실패 응답을 성공으로 오인하지 않도록 memberService 와 동일하게
isSuccess 검사 추가

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
yhi9839 and others added 6 commits June 22, 2026 22:23
- 모바일에서 독서모임/사용자추천 세로 정렬(flex-col t:flex-row)
- 사용자 추천을 ListSubscribeLarge 단일 컴포넌트로 통일(모바일 전용 분기 제거)
- ListSubscribeLarge 폭을 모바일 전체폭/태블릿 이상 고정폭으로 반응형 처리
- 홈 독서모임을 모임 화면과 동일한 Mybookclub으로 통일 + 검색/생성 버튼 유지
- 비로그인/추천 0건 시 모바일·태블릿 추천 숨김 및 태블릿 폭 제한(t:max-w-[332px])

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Mybookclub에 선택적 footer prop 추가 → 박스(Subbrown-4) 하단 내부에 렌더
- HomeClubSection이 검색/생성 버튼을 footer로 전달하도록 변경
- footer 기본값 undefined라 Group-Search 등 기존 사용처 영향 없음

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- 전체보기 토글이 보일 때(목록이 한도 초과)는 검색/생성 버튼 숨김, 한도 이내(0개 포함)일 때만 노출
- 태블릿에서 모임 박스를 늘리지 않고 336px 고정폭으로 변경(책이야기 카드와 동일)
- 모임/추천 박스를 gap-5 + 가운데 정렬로 배치해 아래 책이야기 2열 그리드와 폭·정렬 일치
- 불필요해진 t:max-w-[332px] 조건 클래스 제거

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Mybookclub에 선택적 singleColumn prop 추가 → true면 전 화면 1열, 기본은 기존 태블릿 2열 유지
- 홈(HomeClubSection)에서 singleColumn 전달 → 태블릿 모임 목록을 데스크탑과 동일하게 1열로 표시
- 모임 검색 페이지(GroupsPageClient)는 prop 미전달이라 태블릿 2열 그대로 유지
- 토글 기준은 태블릿 limit=4 유지(5개 이상부터 전체보기)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- ListSubscribeLarge에 hideTitle prop 추가 → 박스 안 "사용자 추천" 제목 숨김 옵션
- HomeRecommendationSection이 독서모임과 동일한 스타일/글자크기로 제목을 박스 위에 렌더(hideTitle 전달)
- 추천 박스 높이를 고정(h-[424px]) → h-auto로 변경해 모바일/태블릿 하단 빈 공간 제거
- 데스크탑 주입(HomeStoryList)·책이야기 페이지(StoriesPageClient)는 기존 내부 제목/고정 높이 유지

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- 본문 컨테이너가 태블릿에서 패딩 0이라 제목/본문이 가장자리에 붙어 잘리던 문제 해결
- 홈/메인과 동일한 px-4 t:px-6 적용, 데스크탑에서는 히어로 상단 내비와 정렬

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@shinwokkang

Copy link
Copy Markdown
Contributor

수고하셨습니다 ! 이 PR 은 충돌 확인만 해주시면 될 것 같습니당

yhi9839 and others added 2 commits June 24, 2026 19:23
refactor: 홈 화면 반응형 정리 및 모임·추천 컴포넌트 통일 (+ 소식 상세 여백 보정)
충돌 해결: src/components/base-ui/Comment/comment_section_notice.tsx
- import 블록 양쪽 모두 유지 (ReportReason + isValidUrl/DEFAULT_PROFILE_IMAGE)
- 신고 API 개편(fix-403)과 댓글 프로필 폴백(dev) 변경은 서로 다른 영역이라 둘 다 반영

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@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.

🧹 Nitpick comments (1)
src/components/base-ui/home/Club/HomeClubSection.tsx (1)

68-75: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low value

Non-descriptive alt on decorative icon.

The plus icon uses alt="icon_plus", which is read literally by screen readers and adds noise next to the existing "모임 생성하기" label. Since the icon is decorative here, prefer an empty alt.

Proposed tweak
         <Image
           src="/icon_plus.svg"
-          alt="icon_plus"
+          alt=""
           width={24}
           height={24}
           className="w-3.5 h-3.5 t:w-6 t:h-6"
         />
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/base-ui/home/Club/HomeClubSection.tsx` around lines 68 - 75,
The plus icon in HomeClubSection is decorative, but its Image alt text is
descriptive and gets read by screen readers. Update the Image in HomeClubSection
to use an empty alt for the plus icon, keeping the visible "모임 생성하기" text as the
accessible label.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/components/base-ui/home/Club/HomeClubSection.tsx`:
- Around line 68-75: The plus icon in HomeClubSection is decorative, but its
Image alt text is descriptive and gets read by screen readers. Update the Image
in HomeClubSection to use an empty alt for the plus icon, keeping the visible
"모임 생성하기" text as the accessible label.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 365a2cdb-f477-4336-8989-23058516ebad

📥 Commits

Reviewing files that changed from the base of the PR and between ce5c28d and ecabc89.

📒 Files selected for processing (9)
  • src/app/(main)/home/HomePageClient.tsx
  • src/app/(main)/news/[id]/NewsDetailClient.tsx
  • src/components/base-ui/Comment/comment_section_notice.tsx
  • src/components/base-ui/Group-Search/search_mybookclub.tsx
  • src/components/base-ui/home/Club/HomeClubSection.tsx
  • src/components/base-ui/home/Recommendation/HomeRecommendationSection.tsx
  • src/components/base-ui/home/Recommendation/list_subscribe_large.tsx
  • src/hooks/mutations/useMemberMutations.ts
  • src/services/reportService.ts
✅ Files skipped from review due to trivial changes (1)
  • src/app/(main)/news/[id]/NewsDetailClient.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/hooks/mutations/useMemberMutations.ts
  • src/services/reportService.ts
  • src/components/base-ui/Comment/comment_section_notice.tsx

@yhi9839
yhi9839 merged commit eea9b0d into main Jun 25, 2026
3 checks passed

This branch was successfully deployed

1 active deployment
Preview — ecabc89d Deployed Jun 24, 2026 by vercel[bot]
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.

fix: 신고/차단 기능 수정

2 participants