Skip to content

Fix: 이미지 관련 문의사항 해결#204

Merged
seung365 merged 10 commits into
developfrom
fix/input-image/#201
Aug 25, 2025
Merged

Fix: 이미지 관련 문의사항 해결#204
seung365 merged 10 commits into
developfrom
fix/input-image/#201

Conversation

@seung365
Copy link
Copy Markdown
Member

@seung365 seung365 commented Aug 25, 2025

📌 Summary

📚 Tasks

  • 모바일 내에서 편지 쓰기 내 이미지 첨부가 간헐적으로 안되는 현상 해결
  • 사진이 없을때 objectKey 없이 put 하도록 수정
  • 편지 작성과 동시에 presigned url에 put 하는 방식으로 수정

👀 To Reviewer

디스코드 내에서 논의된 백엔드 측 요구사항 및 오류 제보 사항 반영건입니다.

Summary by CodeRabbit

  • 신기능

    • 글쓰기 모달에서 이미지 파일 선택 즉시 미리보기 지원
    • 제출 시에만 파일 업로드되어 객체 키가 자동 연결
    • 확인 팝업에 로딩 상태(isLoading) 표시, 업로드 중 버튼 문구 “업로드 중...” 표시
    • 이미지 없이도 제출 가능
  • 개선

    • 업로드 실패 시 경고 메시지 및 에러 처리 강화
    • 이미지 추가 흐름을 라벨+숨김 입력 방식으로 단순화
  • 스타일

    • 파일 입력 요소를 숨기는 스타일 추가
  • 잡무

    • 스토리북에 확인 팝업의 isLoading 속성 사용 예시 추가

commit c07799a
Merge: 0b2fa2b 6d6f73e
Author: 백승범 <bdh3659@naver.com>
Date:   Sat Aug 23 00:58:43 2025 +0900

    Merge branch 'develop' of https://github.com/YAPP-Github/26th-Web-Team-3-FE into qa/additional/#199

commit 0b2fa2b
Author: 백승범 <bdh3659@naver.com>
Date:   Sat Aug 23 00:43:48 2025 +0900

    style: grid-layout 모바일 view 수정

commit 278afe5
Author: 백승범 <bdh3659@naver.com>
Date:   Sat Aug 23 00:24:26 2025 +0900

    fix: 편지 담기 reset 추가

commit 6d6f73e
Author: beom <74394824+seung365@users.noreply.github.com>
Date:   Sat Aug 23 00:05:59 2025 +0900

    fix: 모달 닫힘 경고 팝업 뜨도록 수정 및 esc props 전달 (#198)
@seung365 seung365 self-assigned this Aug 25, 2025
@seung365 seung365 requested a review from seueooo as a code owner August 25, 2025 00:50
@vercel
Copy link
Copy Markdown

vercel Bot commented Aug 25, 2025

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

Project Deployment Preview Comments Updated (UTC)
time-capsule Ready Ready Preview Comment Aug 25, 2025 1:10am

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Aug 25, 2025

Warning

Rate limit exceeded

@seung365 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 11 minutes and 39 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between d62b829 and 03f9727.

📒 Files selected for processing (1)
  • app/(sub)/capsule-detail/_components/write-modal/_hooks/use-image-upload.ts (1 hunks)

Walkthrough

이미지 업로드 훅을 파일 선택/미리보기 중심 API로 전면 개편했고, 작성 모달이 이에 맞게 제출 플로우를 수정했습니다. 파일 업로드 뮤테이션의 기본 성공/실패 콜백을 제거했으며, 편지 작성 타입의 objectKey를 선택적으로 변경했습니다. 확인 팝업은 로딩 상태를 지원합니다. 숨김 파일 입력용 스타일이 추가되었습니다.

Changes

Cohort / File(s) Summary
Image upload hook refactor
app/(sub)/capsule-detail/_components/write-modal/_hooks/use-image-upload.ts
훅 시그니처 변경(매개변수 제거), 반환 API 교체: previewUrl/handleFileChange/removeImage/uploadFile/hasFile/isUploading. 파일 선택/미리보기 상태 추가 및 Object URL 정리. 업로드는 Promise로 objectKey 반환. 기존 onObjectKeyChange/handleImageUpload 제거.
Write modal integration
app/(sub)/capsule-detail/_components/write-modal/index.tsx
새 훅 API로 연동. 제출 시 파일 존재 시 업로드 후 objectKey 포함, 없으면 제거. 비동기 가드(isPending/isUploading), 에러 처리 추가. 미리보기/파일 입력 UI 갱신. 팝업에 isLoading 전달.
Upload mutation side-effects removal
shared/api/mutations/file.ts
useFileUpload에서 onSuccess/onError 기본 콜백 제거. mutationFn 동작(Pre-signed URL→PUT→검증→objectKey 반환)은 동일. 호출자가 핸들러를 제공해야 함.
API type update
shared/types/api/letter.ts
WriteLetterReq의 objectKey를 선택적(objectKey?: string)으로 변경.
Popup loading state
shared/ui/popup/popup-confirm-letter/index.tsx, shared/ui/popup/popup.stories.tsx
PopupConfirmLetter에 isLoading(boolean) prop 추가. 로딩 시 버튼 대신 스피너 렌더. 스토리 사용 예 갱신.
Hidden file input style
app/(sub)/capsule-detail/_components/write-modal/write-modal.css.ts
새 style export: imageInput(display: "none") 추가.

Sequence Diagram(s)

sequenceDiagram
  actor U as User
  participant WM as WriteModal
  participant IU as useImageUpload
  participant FU as useFileUpload (mutation)
  participant API as File API

  rect rgb(240,248,255)
  note right of U: 이미지 선택
  U->>WM: 파일 선택
  WM->>IU: handleFileChange(File)
  IU-->>WM: previewUrl 설정
  end

  rect rgb(245,255,250)
  note right of U: 제출(confirm)
  U->>WM: 편지 담기
  WM->>WM: isPending/isUploading 가드
  alt 파일 있음
    WM->>IU: uploadFile()
    IU->>FU: mutateAsync(file)
    FU->>API: GET presigned URL
    FU->>API: PUT file
    API-->>FU: 200 OK + objectKey
    FU-->>IU: objectKey
    IU-->>WM: objectKey
  else 파일 없음
    WM->>WM: objectKey undefined
  end
  WM->>WM: submit(payload)
  WM-->>U: 성공 후 리셋/미리보기 제거
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/input-image/#201

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Aug 25, 2025

🚀 Storybook 배포

📖 Storybook: https://683d91ab23651aa0b399e435-xgdtokadlx.chromatic.com/
🔗 Chromatic Build: https://www.chromatic.com/build?appId=683d91ab23651aa0b399e435&number=226
✅ Status: success

@github-actions
Copy link
Copy Markdown

This pull request (commit d62b829) has been deployed to Vercel ▲ - View GitHub Actions Workflow Logs

Name Link
🌐 Unique https://time-capsule-46v1rjiy7-hs-projects-b4a69d5f.vercel.app
🔍 Inspect https://vercel.com/hs-projects-b4a69d5f/time-capsule/FAwex2n47uTGbRYBqvPRZJ4khdks

Copy link
Copy Markdown

@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: 2

🧹 Nitpick comments (13)
app/(sub)/capsule-detail/_components/write-modal/write-modal.css.ts (1)

178-181: display: none 대신 시각적 숨김(SR-only) 패턴 사용 제안

파일 입력을 display: none으로 숨기면 스크린 리더 포커스 트리에서 완전히 제외됩니다. 라벨 클릭으로 동작은 하지만 접근성 관점에서는 시각적 숨김 패턴을 권장합니다.

아래처럼 교체하면 키보드/보조공학 기기 호환성이 좋아집니다. 라벨의 htmlFor/id 연결도 함께 확인해주세요.

-export const imageInput = style({
-  display: "none",
-});
+export const imageInput = style({
+  position: "absolute",
+  width: "1px",
+  height: "1px",
+  padding: 0,
+  margin: "-1px",
+  overflow: "hidden",
+  clip: "rect(0 0 0 0)",
+  clipPath: "inset(50%)",
+  whiteSpace: "nowrap",
+  border: 0,
+});
shared/ui/popup/popup-confirm-letter/index.tsx (3)

5-5: 로더 색상 themeVars 사용 및 a11y 속성 추가

디자인 토큰 일관성(다크/라이트 테마 대응)과 접근성 향상을 위해 로더 색상을 themeVars로, 로더 컨테이너에 상태 전달 속성을 추가하는 것을 권장합니다.

 import Image from "next/image";
-import { PulseLoader } from "react-spinners";
+import { PulseLoader } from "react-spinners";
+import { themeVars } from "@/shared/styles/base/theme.css";
@@
-        {isLoading ? (
-          <PulseLoader color="white" size={10} />
+        {isLoading ? (
+          <div role="status" aria-live="polite">
+            <PulseLoader color={themeVars.color.white[100]} size={10} />
+          </div>
         ) : (

Also applies to: 34-36


8-14: isLoading 기본값 제공으로 이전 호출부 안전성 확보

타 호출부가 아직 업데이트되지 않았을 가능성에 대비해 기본값을 두면 안전합니다. 타입은 그대로 required여도 런타임 안전성이 올라갑니다.

-const PopupConfirmLetter = ({
-  isLoading,
+const PopupConfirmLetter = ({
+  isLoading = false,
   openDate,
   isOpen,
   close,
   onConfirm,
 }: PopupConfirmLetterProps) => {

34-45: 로딩 시 버튼 언마운트 대신 disabled 처리로 포커스/레이아웃 안정성 개선

로딩 중 버튼을 제거하면 포커스 손실/레이아웃 점프가 발생할 수 있습니다. 동일한 영역을 유지하며 버튼을 비활성화하는 패턴을 권장합니다. 필요 시 스피너는 버튼 옆에 배치하세요.

-        {isLoading ? (
-          <div role="status" aria-live="polite">
-            <PulseLoader color={themeVars.color.white[100]} size={10} />
-          </div>
-        ) : (
-          <>
-            <Popup.Button onClick={close} className={styles.content}>
-              계속 쓰기
-            </Popup.Button>
-            <Popup.Button className={styles.putButton} onClick={onConfirm}>
-              편지 담기
-            </Popup.Button>
-          </>
-        )}
+        <>
+          {isLoading && (
+            <div role="status" aria-live="polite" style={{ display: "flex", justifyContent: "center", width: "100%" }}>
+              <PulseLoader color={themeVars.color.white[100]} size={10} />
+            </div>
+          )}
+          <Popup.Button
+            onClick={close}
+            className={styles.content}
+            disabled={isLoading}
+            aria-disabled={isLoading}
+          >
+            계속 쓰기
+          </Popup.Button>
+          <Popup.Button
+            className={styles.putButton}
+            onClick={onConfirm}
+            disabled={isLoading}
+            aria-disabled={isLoading}
+          >
+            편지 담기
+          </Popup.Button>
+        </>
shared/ui/popup/popup.stories.tsx (1)

216-226: ConfirmLetter 스토리에 로딩 상태 예시 추가 제안

isLoading={false}만 있으면 스피너 UI 회귀 테스트가 어렵습니다. 로딩 전용 스토리를 하나 더 두면 시각/동작 확인이 쉬워집니다.

export const ConfirmLetterLoading: Story = {
  render: () => (
    <button
      style={{ padding: "10px 20px", borderRadius: "12px" }}
      onClick={() => {
        overlay.open(({ isOpen, close }) => (
          <PopupConfirmLetter
            isLoading={true}
            openDate="2025. 06. 25"
            isOpen={isOpen}
            close={close}
            onConfirm={() => {}}
          />
        ));
      }}
    >
      Open Popup (Loading)
    </button>
  ),
};
app/(sub)/capsule-detail/_components/write-modal/_hooks/use-image-upload.ts (3)

23-37: 파일 확장자/형식 검증과 입력 초기화

  • alert는 훅 레벨에서 지양(테스트/UX 방해). 로그 또는 상위 컴포넌트로 에러 전달 권장.
  • 확장자는 소문자로 정규화.
  • 동일 파일 재선택 시 change 이벤트가 발생하도록 input 값을 초기화.
  • (선택) 허용 확장자 화이트리스트로 조기 차단.
-    const extension = file.name.split(".").pop();
-    if (!extension) {
-      alert("파일 확장자를 찾을 수 없습니다.");
-      return;
-    }
+    const extension = file.name.split(".").pop()?.toLowerCase();
+    if (!extension) {
+      console.warn("파일 확장자를 찾을 수 없습니다.");
+      return;
+    }
+    const allowed = new Set(["jpg", "jpeg", "png", "webp", "heic", "heif", "gif"]);
+    if (!allowed.has(extension)) {
+      console.warn(`허용되지 않은 파일 형식: ${extension}`);
+      return;
+    }
@@
-    setSelectedFile(file);
-    setPreviewUrl(objectUrl);
+    setSelectedFile(file);
+    setPreviewUrl(objectUrl);
+    // 동일 파일 재선택 허용
+    e.currentTarget.value = "";

39-58: 업로드 전 용량 제한 및 확장자 검증을 통일

대용량 이미지(특히 모바일 촬영 원본)는 업로드/메모리 비용이 큽니다. 업로드 전에 크기/형식 검사를 통일해 조기 실패시키면 UX/리소스 절약에 유리합니다.

-  const uploadFile = async (): Promise<string> => {
+  const uploadFile = async (): Promise<string> => {
     if (!selectedFile) {
       throw new Error("선택된 파일이 없습니다.");
     }
 
     const fileName = "LETTER";
-    const extension = selectedFile.name.split(".").pop();
-
-    if (!extension) {
-      throw new Error("파일 확장자를 찾을 수 없습니다.");
-    }
+    const extension = selectedFile.name.split(".").pop()?.toLowerCase();
+    if (!extension) throw new Error("파일 확장자를 찾을 수 없습니다.");
+    const allowed = new Set(["jpg", "jpeg", "png", "webp", "heic", "heif", "gif"]);
+    if (!allowed.has(extension)) throw new Error(`허용되지 않은 파일 형식: ${extension}`);
+    const MAX_MB = 10;
+    if (selectedFile.size > MAX_MB * 1024 * 1024) {
+      throw new Error(`파일 최대 크기 ${MAX_MB}MB를 초과했습니다.`);
+    }

(선택) allowed/최대 용량 상수는 훅 상단의 모듈 상수로 올려 DRY하게 관리하면 더 좋습니다.


9-16: 미세 최적화: revoke 시점 단일화

현재 useEffect cleanup과 removeImage 양쪽에서 URL.revokeObjectURL이 실행될 수 있습니다(중복 호출은 무해하지만 중복입니다). cleanup 하나로 통일하면 간결해집니다.

   useEffect(() => {
     return () => {
       if (previewUrl) {
         URL.revokeObjectURL(previewUrl);
       }
     };
   }, [previewUrl]);

removeImage에서는 state만 초기화하도록 단순화:

-  const removeImage = () => {
-    if (previewUrl) {
-      URL.revokeObjectURL(previewUrl);
-    }
-    setPreviewUrl(null);
-    setSelectedFile(null);
-  };
+  const removeImage = () => {
+    setPreviewUrl(null);
+    setSelectedFile(null);
+  };
app/(sub)/capsule-detail/_components/write-modal/index.tsx (5)

74-116: 현재는 순차 처리(업로드 완료 후 편지 생성). PR 목표의 ‘동시 PUT’과는 다를 수 있음

handleConfirm에서 await uploadFile() 후에 writeLetterMutate를 호출하므로 실질적으로 직렬 흐름입니다. 백엔드가 objectKey를 사전 발급하고 PUT 완료를 동기화할 필요가 없다면, 다음 접근으로 체감 지연을 줄일 수 있습니다:

  • 업로드 시작 시점에 objectKey를 먼저 확보하고(훅에서 presign 응답 즉시 반환), PUT은 백그라운드로 진행.
  • useWriteLettermutateAsync를 사용해 Promise 기반으로 처리하고, 업로드 PUT과 편지 생성 API를 Promise.all로 동기화(둘 중 하나 실패 시 일관된 에러 핸들링).
  • 실패 시 orphan object 정리 전략(필요 시) 정의.

백엔드 계약이 “편지 생성 시 objectKey 필요, PUT 완료는 비동기 허용”인지 확인 부탁드립니다. 허용된다면, 훅을 startUpload(): { objectKey, putPromise } 형태로 분리하는 리팩터가 적합합니다.


194-211: blob URL 미리보기는 Next/Image 최적화 우회가 필요할 수 있음 + 접근성 소폭 보완

일부 Next.js 버전/설정에서 blob: URL은 이미지 최적화 대상이 아니어서 경고가 발생하거나 렌더링이 실패할 수 있습니다. 안전하게 unoptimized를 추가하는 것을 권장합니다. 또한 삭제 버튼에 스크린리더용 라벨을 추가하면 접근성이 개선됩니다.

적용 제안:

-                    <button
+                    <button
                       type="button"
                       onClick={removeImage}
                       className={styles.removeImageButton}
+                      aria-label="이미지 삭제"
                     >
...
-                    <Image
+                    <Image
                       src={previewUrl}
-                      alt="업로드된 이미지"
+                      alt="선택한 이미지 미리보기"
                       width={80}
                       height={80}
                       className={styles.imagePreview}
+                      unoptimized
                     />

iOS Safari(특히 저사양 기기)에서 blob 미리보기/스크롤 성능도 한 번만 실기기로 확인 부탁드립니다.


213-221: 숨김 파일 입력 스타일 class 사용 및 비활성 조건 확장 제안

CSS 모듈로 imageInput 스타일이 제공된다면 inline style 대신 class 사용이 일관성/오버라이드 측면에서 안전합니다. 또한 제출 중(isPending)에도 파일 선택을 막아 레이스를 줄이는 것이 좋습니다.

-                      <input
+                      <input
                         type="file"
                         accept="image/*"
                         onChange={handleFileChange}
-                        disabled={isUploading}
-                        style={{ display: "none" }}
+                        disabled={isUploading || isPending}
+                        className={styles.imageInput}
+                        capture="environment"  // 모바일 카메라 우선(옵션)
                       />

255-255: isPending || isUploading 반복 사용을 상수로 통일

파일 전역에서 자주 쓰이므로 const isLoading = isPending || isUploading;로 통일하면 가독성과 변경 용이성이 올라갑니다(제출 버튼 disabled/로더, Confirm 모달 isLoading에 공통 사용).


282-286: reset 시 objectKey는 폼 필드가 아니므로 생략 가능 + 초기화 로직 DRY

objectKey는 RHF로 관리되는 필드가 아니므로 reset 인자에서 제외해도 됩니다. 또한 성공/뒤로가기에서 동일한 초기화(removeImage 포함)를 반복하니 헬퍼로 추출하면 유지보수가 쉬워집니다.

간단 수정:

           reset({
             capsuleId: capsuleData.result.id.toString(),
             content: "",
             from: "",
-            objectKey: undefined,
           });

그리고 다음과 같은 헬퍼로 중복 제거(예시):

const resetFormAndImage = () => {
  reset({ capsuleId: capsuleData.result.id.toString(), content: "", from: "" });
  if (previewUrl) removeImage();
};
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between a86f47b and d62b829.

📒 Files selected for processing (7)
  • app/(sub)/capsule-detail/_components/write-modal/_hooks/use-image-upload.ts (1 hunks)
  • app/(sub)/capsule-detail/_components/write-modal/index.tsx (8 hunks)
  • app/(sub)/capsule-detail/_components/write-modal/write-modal.css.ts (1 hunks)
  • shared/api/mutations/file.ts (0 hunks)
  • shared/types/api/letter.ts (1 hunks)
  • shared/ui/popup/popup-confirm-letter/index.tsx (2 hunks)
  • shared/ui/popup/popup.stories.tsx (2 hunks)
💤 Files with no reviewable changes (1)
  • shared/api/mutations/file.ts
🧰 Additional context used
🧬 Code graph analysis (2)
app/(sub)/capsule-detail/_components/write-modal/_hooks/use-image-upload.ts (1)
shared/api/mutations/file.ts (1)
  • useFileUpload (5-34)
app/(sub)/capsule-detail/_components/write-modal/index.tsx (2)
shared/types/api/letter.ts (1)
  • WriteLetterReq (32-37)
app/(sub)/capsule-detail/_components/write-modal/_hooks/use-image-upload.ts (1)
  • useImageUpload (4-76)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: deploy
🔇 Additional comments (6)
shared/types/api/letter.ts (1)

35-36: objectKey optional 적용 검증 및 서버 처리 확인 필요

  • 클라이언트에서 이미지가 없을 때 objectKey를 완전히 생략하지 않고 명시적으로 undefined로 전송하고 있습니다
    • app/(sub)/capsule-detail/_components/write-modal/index.tsx:94
    • app/(sub)/capsule-detail/_components/write-modal/index.tsx:282
  • 서버 측 DTO/Bean Validation/Zod/OpenAPI 스키마 등이 objectKeyundefined 혹은 누락된 경우에도 동일하게 처리되도록 보장되어야 합니다
  • 직렬화 과정에서 objectKey가 빈 문자열("")로 전송되지 않도록(기본 제외되더라도) 설정을 재확인해 주세요

백엔드 처리 로직과 클라이언트 직렬화 설정을 한 번 더 점검해 주시면 좋겠습니다.

shared/ui/popup/popup.stories.tsx (1)

134-138: 형식 정리 OK

경고 팝업 스토리의 prop 개행 정리는 가독성에 도움 됩니다.

app/(sub)/capsule-detail/_components/write-modal/_hooks/use-image-upload.ts (1)

68-75: API 사용은 적절합니다

  • mutateAsync로 objectKey를 직접 반환받는 구조가 이번 플로우(이미지 있을 때만 업로드)에 잘 맞습니다.
  • hasFile/isUploading 제공으로 상위 컴포넌트 제어가 명확합니다.
app/(sub)/capsule-detail/_components/write-modal/index.tsx (3)

39-45: react-hook-form 기본값/타입 정합성 OK

objectKey를 기본값에서 제거하고 타입(WriteLetterReq의 optional)과 정합성을 맞춘 점 좋습니다.


57-64: 새 useImageUpload 훅 연동 적절

미리보기/업로드 상태(hasFile, isUploading)와 액션(handleFileChange, removeImage, uploadFile)만 노출하는 인터페이스로 깔끔하게 분리되어 있어 모달 측 복잡도가 낮아졌습니다.


122-122: 작성 중 경고 조건 정의 적절

내용/보낸이/이미지 미리보기 중 하나라도 있으면 경고 노출하는 로직이 기대 동작과 부합합니다.

Comment thread app/(sub)/capsule-detail/_components/write-modal/_hooks/use-image-upload.ts Outdated
@github-actions
Copy link
Copy Markdown

This pull request (commit 03f9727) has been deployed to Vercel ▲ - View GitHub Actions Workflow Logs

Name Link
🌐 Unique https://time-capsule-b6ek8xpgy-hs-projects-b4a69d5f.vercel.app
🔍 Inspect https://vercel.com/hs-projects-b4a69d5f/time-capsule/6NL3t8HKFsBesVsBCcDVnQNYFXkA

Copy link
Copy Markdown
Contributor

@seueooo seueooo left a comment

Choose a reason for hiding this comment

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

역싀👍👍

@seung365 seung365 merged commit 37dca81 into develop Aug 25, 2025
10 checks passed
@seung365 seung365 linked an issue Aug 25, 2025 that may be closed by this pull request
seung365 added a commit that referenced this pull request Aug 30, 2025
commit 37dca81
Author: beom <74394824+seung365@users.noreply.github.com>
Date:   Mon Aug 25 12:48:52 2025 +0900

    Fix: 이미지 관련 문의사항 해결 (#204)

    * fix: 모달 닫힘 경고 팝업 뜨도록 수정 및 esc props 전달

    * Squashed commit of the following:

    commit c07799a
    Merge: 0b2fa2b 6d6f73e
    Author: 백승범 <bdh3659@naver.com>
    Date:   Sat Aug 23 00:58:43 2025 +0900

        Merge branch 'develop' of https://github.com/YAPP-Github/26th-Web-Team-3-FE into qa/additional/#199

    commit 0b2fa2b
    Author: 백승범 <bdh3659@naver.com>
    Date:   Sat Aug 23 00:43:48 2025 +0900

        style: grid-layout 모바일 view 수정

    commit 278afe5
    Author: 백승범 <bdh3659@naver.com>
    Date:   Sat Aug 23 00:24:26 2025 +0900

        fix: 편지 담기 reset 추가

    commit 6d6f73e
    Author: beom <74394824+seung365@users.noreply.github.com>
    Date:   Sat Aug 23 00:05:59 2025 +0900

        fix: 모달 닫힘 경고 팝업 뜨도록 수정 및 esc props 전달 (#198)

    * fix: 모바일에서 간헐적으로 이미지 업로드 안되는 현상 수정

    * feat: objectKey를 선택적 속성으로 변경

    * feat: 사진 업로드 로직 변경

    * chore: 줄간격 추가

    * chore: type 충돌 해결

    * chore: 코드 리뷰 반영

commit 5c19df6
Author: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Date:   Mon Aug 25 00:53:03 2025 +0000

    Update dev dependencies (#203)

    Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

commit a86f47b
Author: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Date:   Sun Aug 24 22:01:52 2025 +0000

    Update all non-major dependencies (#202)

    Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

commit b23c714
Author: beom <74394824+seung365@users.noreply.github.com>
Date:   Sat Aug 23 01:05:36 2025 +0900

    QA: 추가 QA 반영 (#200)

    * fix: 모달 닫힘 경고 팝업 뜨도록 수정 및 esc props 전달

    * fix: 편지 담기 reset 추가

    * style: grid-layout 모바일 view 수정

commit 6d6f73e
Author: beom <74394824+seung365@users.noreply.github.com>
Date:   Sat Aug 23 00:05:59 2025 +0900

    fix: 모달 닫힘 경고 팝업 뜨도록 수정 및 esc props 전달 (#198)
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