Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (3)
Walkthrough텍스트 에디터에 이미지 첨부 기능을 추가하고, 프로젝트 상세에 이미지를 렌더링하는 새로운 컴포넌트를 통합했습니다. 이미지 업로드 API 및 폼 스키마/타입이 확장되었고, 일부 UI 레이아웃과 바텀시트/오버레이 표시 로직이 조정되었습니다. Changes
Sequence DiagramsequenceDiagram
actor User
participant PostImage as PostImage(Component)
participant FormContext as FormProvider/useFormContext
participant API as Image API
participant S3 as S3 Storage
User->>PostImage: 파일 선택 (input[file])
PostImage->>API: uploadPostImages(files)
API->>API: getPostImagePresignedUrls(fileNames[])
API-->>PostImage: [{ preSignedUrl, objectKey }, ...]
par 병렬 업로드
PostImage->>S3: PUT file[0] -> preSignedUrl (x-amz-acl: public-read)
PostImage->>S3: PUT file[1] -> preSignedUrl (x-amz-acl: public-read)
S3-->>PostImage: 200 OK
end
PostImage->>PostImage: preview URL 생성 (createObjectURL)
PostImage->>FormContext: setValue('imageKeys', [objectKey,...])
FormContext-->>PostImage: 값 갱신 확인
User->>PostImage: 이미지 삭제 클릭
PostImage->>PostImage: revokeObjectURL, state 업데이트
PostImage->>FormContext: setValue('imageKeys', updated[])
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/app/(main)/teampsylog/_components/KeywordGuideOverlay.tsx (1)
66-81:⚠️ Potential issue | 🟡 Minor데스크톱에서 "다시 보지 않기" 기능이 비활성화되어 매번 오버레이가 재노출됩니다
라인 66-81의 체크박스 코드가 주석 처리되어 데스크톱 사용자는
handleClick을 실행할 수 없습니다. 현재 데스크톱의 "튜토리얼 마치기" 버튼은onClose만 호출하므로localStorage.setItem('hideKeywordGuide', 'true')이 실행되지 않고, 오버레이가 매번 다시 노출됩니다. 모바일은 체크박스가 활성화되어 있어 정상 작동합니다.주석 처리된 체크박스를 활성화하거나, 버튼 클릭 시 localStorage 저장 로직을 추가하여 데스크톱에서도 "다시 보지 않기" 기능을 동작하도록 수정해주세요.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/app/`(main)/teampsylog/_components/KeywordGuideOverlay.tsx around lines 66 - 81, The desktop overlay never persists "do not show again" because the checkbox block in KeywordGuideOverlay is commented out so handleClick is never reachable; either restore that checkbox UI (the commented label/input block) so users can toggle checked and trigger handleClick, or ensure the tutorial finish flow also writes localStorage.setItem('hideKeywordGuide','true') before calling onClose; update the component's finish button handler (the function that calls onClose) or onClose itself to call localStorage.setItem('hideKeywordGuide','true') when checked/when user explicitly chooses to hide, and keep handleClick, checked, and hideKeywordGuide key names consistent.
🧹 Nitpick comments (1)
src/app/(main)/project/[id]/_components/ProjectImage.tsx (1)
1-4: 이 컴포넌트는images만 받도록 좁히는 편이 좋겠습니다.Line 4처럼
ResponseProject전체를 props로 받으면 실제로 쓰지 않는 필드까지 public API가 됩니다.images만 받도록 좁혀 두면 상세 응답 타입 변화가 여기까지 전파되지 않습니다.수정 예시
-import { ResponseProject } from '@/types/project'; +import { ProjectImage as ProjectImageItem } from '@/types/project'; import Image from 'next/image'; -const ProjectImage = ({ images }: ResponseProject) => { +type ProjectImageProps = { + images?: ProjectImageItem[]; +}; + +const ProjectImage = ({ images }: ProjectImageProps) => {- <ProjectImage {...data} /> + <ProjectImage images={data.images} />🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/app/`(main)/project/[id]/_components/ProjectImage.tsx around lines 1 - 4, The ProjectImage component currently types its props as ResponseProject which exposes the whole response; narrow the prop type to only images by updating the ProjectImage signature to accept a single prop named images typed as ResponseProject['images'] (or the concrete images type) and remove the unused ResponseProject usage in props, ensuring references inside ProjectImage still use the images variable; this prevents unrelated ResponseProject shape changes from affecting this component.
🤖 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/app/`(main)/project/_components/ProjectList.tsx:
- Line 110: The empty-state span still uses a hardcoded col-span-3 which breaks
tablet layout; locate the empty-state element in ProjectList (the span/div that
currently has "col-span-3") and make its grid span responsive to match the
container by replacing or augmenting the class with tablet:col-span-2 (e.g.
change "col-span-3" to "desktop:col-span-3 tablet:col-span-2" or add
"tablet:col-span-2" alongside the existing class) so the empty message occupies
two columns on tablet and three on desktop.
In `@src/app/`(main)/teampsylog/_components/BottomComment.tsx:
- Around line 30-35: The close animation is cut off because BottomComment.tsx
toggles display with 'block/hidden' (and a similar 'flex/hidden' later) causing
the element to be removed immediately when isOpen flips; instead keep the
element mounted and control visibility via opacity/transform and pointer-events.
Update BottomComment.tsx to use a stable display (no 'hidden' toggle) and
replace the conditional in className with a pointer-events class (e.g.,
pointer-events-none when shouldShow is false); update the inline style to
animate opacity and transform (slide) based on isDragging, dragCurrentY, isOpen
and isClosing (use the existing calculations used for opacity, extend to
transform translateY) and ensure transition is applied when not dragging. Apply
the same change to the other block (lines ~39-50) that toggles 'flex/hidden'.
Verify interactions tied to handleClose only fire when pointer-events are
enabled. Also ensure coordination with useBottomSheetDrag.tsx's shouldShow and
LogNote.tsx's isOpen paths so the element remains mounted during the closing
animation.
In `@src/components/recruit/RecruitForm.tsx`:
- Around line 86-95: The deadline validation logic in ProjectDate is inverted:
the UI currently shows the error when deadline > startDate and otherwise only
shows errors.deadline, letting invalid dates pass and lacking resolver-level
checks; update the validation by moving this rule into the form schema (use
Zod.refine) to assert deadline > startDate (or use a shared isValid-like
predicate), remove the inverted check around isEndDateInvalid in the RecruitForm
ProjectDate props (deadline, startDate, control, errors), and ensure the
resolver returns errors.deadline when the refine fails so the component displays
the validation message consistently from the schema.
In `@src/components/recruit/useRecruitForm.ts`:
- Around line 67-68: The form initializes imageKeys only from
initialData.images, losing values when the server returns initialData.imageKeys;
update the initialization in useRecruitForm so imageKeys uses
initialData.imageKeys when present (falling back to mapping initialData.images
to img.objectKey or to an empty array), i.e. change the imageKeys expression to
prefer initialData?.imageKeys and otherwise derive from initialData?.images to
preserve existing attachments when opening the editor.
In `@src/libs/api/image.ts`:
- Around line 80-87: The code currently assumes presignedList and files are in
the same order which can break mapping; first validate presignedList.length ===
files.length and throw a clear error if not, then iterate over the files array
(not presignedList) and for each file locate the corresponding presigned entry
(e.g., find entry in presignedList where objectKey or preSignedUrl maps to
file.name, e.g., objectKey.endsWith(file.name) or other project-specific match),
call uploadToS3 with that entry.preSignedUrl and the file, and push the matched
entry.objectKey; if no match is found for a file, throw an error so uploads can
fail-fast. Ensure you update the code paths using presignedList,
getPostImagePresignedUrls, uploadToS3, files, and objectKey accordingly.
- Line 11: The uploadToS3 function currently hardcodes the 'x-amz-acl':
'public-read' header causing all uploads (including profile images) to be
public; change uploadToS3 to accept an optional acl parameter (or options
object) instead of a fixed ACL, remove the hardcoded 'x-amz-acl' entry and only
set that header when acl is provided, then update callers (e.g.,
useUploadProfileImage.ts) to pass a suitable ACL (e.g., 'private' for profile
images, 'public-read' for public post images) so access control is handled per
upload.
---
Outside diff comments:
In `@src/app/`(main)/teampsylog/_components/KeywordGuideOverlay.tsx:
- Around line 66-81: The desktop overlay never persists "do not show again"
because the checkbox block in KeywordGuideOverlay is commented out so
handleClick is never reachable; either restore that checkbox UI (the commented
label/input block) so users can toggle checked and trigger handleClick, or
ensure the tutorial finish flow also writes
localStorage.setItem('hideKeywordGuide','true') before calling onClose; update
the component's finish button handler (the function that calls onClose) or
onClose itself to call localStorage.setItem('hideKeywordGuide','true') when
checked/when user explicitly chooses to hide, and keep handleClick, checked, and
hideKeywordGuide key names consistent.
---
Nitpick comments:
In `@src/app/`(main)/project/[id]/_components/ProjectImage.tsx:
- Around line 1-4: The ProjectImage component currently types its props as
ResponseProject which exposes the whole response; narrow the prop type to only
images by updating the ProjectImage signature to accept a single prop named
images typed as ResponseProject['images'] (or the concrete images type) and
remove the unused ResponseProject usage in props, ensuring references inside
ProjectImage still use the images variable; this prevents unrelated
ResponseProject shape changes from affecting this component.
🪄 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: 1507cc76-3ed2-4315-9292-c2677f4186df
📒 Files selected for processing (14)
src/app/(main)/project/[id]/_components/ProjectImage.tsxsrc/app/(main)/project/[id]/_components/ProjectInfo.tsxsrc/app/(main)/project/_components/ProjectList.tsxsrc/app/(main)/teampsylog/_components/BottomComment.tsxsrc/app/(main)/teampsylog/_components/KeywordGuideOverlay.tsxsrc/components/recruit/RecruitForm.tsxsrc/components/recruit/editor/PostImage.tsxsrc/components/recruit/editor/TextContent.tsxsrc/components/recruit/useRecruitForm.tssrc/hooks/queries/useRecruitingPosts.tssrc/libs/api/image.tssrc/libs/api/recruitingPosts.tssrc/libs/schemas/projectSchema.tssrc/types/project.ts
💤 Files with no reviewable changes (2)
- src/hooks/queries/useRecruitingPosts.ts
- src/libs/api/recruitingPosts.ts
✅ PR 유형
어떤 변경 사항이 있었나요?
📌 관련 이슈번호
✅ Key Changes
📸 스크린샷 or 실행영상
🎸 기타 사항 or 추가 코멘트
Summary by CodeRabbit
릴리스 노트
New Features
UI/UX Improvements
Chores