Skip to content

[FIX] TextArea 최소 글자 관련 수정#246

Merged
dodaaaaam merged 2 commits intodevelopfrom
fix/photo-feed-textArea-change(#227)
Feb 12, 2026
Merged

[FIX] TextArea 최소 글자 관련 수정#246
dodaaaaam merged 2 commits intodevelopfrom
fix/photo-feed-textArea-change(#227)

Conversation

@dodaaaaam
Copy link
Contributor

@dodaaaaam dodaaaaam commented Feb 12, 2026

🔀 Pull Request Title

기존 방식: 최소 글자 조건 만족하지 않으면 버튼 자체 disabled
바뀐 방식: 최소 글자 조건을 만족하지 않으면 해당 TextArea에 빨간 테두리 + 최소 글자수 안내
-> 다음 버튼 disabled하지 않고 클릭 시 최소 글자 수를 보여주도록 수정

📌 PR 설명

이번 PR에서 어떤 작업을 했는지 요약해주세요.

  • NewPostPage
  • ReviewPhotoLabPage
  • TextArea
  • scrollToCenter

📷 스크린샷

  • 제목, 내용 둘 다 최소 글자 조건 만족하지 않은 경우, 첫 번째 항목인 제목만 에러 표시
image
  • 제목만 최소 글자 조건 만족하지 않은 경우
image
  • 내용만 최소 글자 조건 만족하지 않은 경우
image

@dodaaaaam dodaaaaam linked an issue Feb 12, 2026 that may be closed by this pull request
@vercel
Copy link

vercel bot commented Feb 12, 2026

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

Project Deployment Actions Updated (UTC)
finders Ready Ready Preview, Comment Feb 12, 2026 0:20am

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @dodaaaaam, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

이 Pull Request는 TextArea 컴포넌트와 이를 사용하는 게시물 작성 페이지들의 사용자 경험을 개선하기 위해 최소 글자 수 유효성 검사 로직을 재정비합니다. 기존에는 유효성 검사 실패 시 단순히 버튼을 비활성화했지만, 이제는 해당 입력 필드에 즉각적인 시각적 피드백(빨간 테두리)과 함께 구체적인 안내 메시지를 제공합니다. 또한, 오류가 발생한 입력 필드로 자동으로 스크롤하고 포커스를 이동시켜 사용자가 문제점을 쉽게 파악하고 수정할 수 있도록 돕습니다.

Highlights

  • TextArea 컴포넌트 확장: forwardRef를 도입하여 TextArea 컴포넌트가 외부 ref를 받을 수 있도록 개선하고, isError prop을 추가하여 유효성 검사 실패 시 시각적 오류 상태를 표시할 수 있게 했습니다.
  • 입력 유효성 검사 UX 개선: 최소 글자 수 조건을 만족하지 못할 경우, 기존의 버튼 비활성화 방식 대신 해당 TextArea에 빨간 테두리로 오류를 표시하고, 사용자에게 최소 글자 수를 안내하는 메시지를 제공하도록 변경했습니다.
  • 오류 필드 자동 스크롤 및 포커스: 유효성 검사 실패 시 해당 TextArea 입력 필드로 자동으로 스크롤하고 포커스를 이동시켜 사용자가 즉시 문제를 인지하고 수정할 수 있도록 사용자 경험을 향상시켰습니다.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • src/components/common/TextArea.tsx
    • forwardRef를 사용하여 TextArea 컴포넌트가 ref를 전달받을 수 있도록 변경했습니다.
    • isError prop을 추가하여 유효성 검사 실패 시 빨간 테두리를 표시하도록 스타일을 조정했습니다.
    • 내부적으로 innerRef와 forwardedRef를 함께 관리하는 로직을 추가했습니다.
  • src/pages/photoFeed/NewPostPage.tsx
    • 제목과 내용 TextArea에 대한 오류 상태(titleError, contentError)와 ref(titleRef, contentRef)를 관리하는 useState 및 useRef 훅을 추가했습니다.
    • handleNext 함수 로직을 수정하여 유효성 검사 실패 시 TextArea에 오류를 표시하고, scrollToCenter 유틸리티를 사용하여 해당 필드로 스크롤 및 포커스하도록 변경했습니다.
    • TextArea 컴포넌트에 ref와 isError prop을 전달하고, onChange 핸들러 내에서 오류 상태를 초기화하는 로직을 추가했습니다.
    • 유효성 검사 실패 시 사용자에게 안내 메시지를 표시하는

      태그를 추가했습니다.

    • "다음" 버튼의 color prop 로직을 canGoNext 대신 isTitleValid && isContentValid로 직접 변경했습니다.
  • src/pages/photoFeed/ReviewPhotoLabPage.tsx
    • 리뷰 텍스트 TextArea에 대한 오류 상태(reviewTextError)와 ref(reviewTextRef)를 관리하는 useState 및 useRef 훅을 추가했습니다.
    • handleTextArea 함수를 새로 추가하여 유효성 검사 실패 시 TextArea에 오류를 표시하고, scrollToCenter 유틸리티를 사용하여 해당 필드로 스크롤 및 포커스하도록 변경했습니다.
    • TextArea 컴포넌트에 ref와 isError prop을 전달하고, onChange 핸들러 내에서 오류 상태를 초기화하는 로직을 추가했습니다.
    • 유효성 검사 실패 시 사용자에게 안내 메시지를 표시하는

      태그를 추가했습니다.

    • "작성 완료" 버튼의 onClick 핸들러를 handleTextArea로 변경하고, disabled prop 로직을 isPending으로만 설정했습니다.
  • src/utils/scrollToCenter.ts
    • 새로운 유틸리티 파일로, 주어진 HTML 요소가 화면 중앙에 오도록 스크롤하는 scrollToCenter 함수를 추가했습니다.
Activity
  • 활동 내역이 제공되지 않았습니다.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

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

Choose a reason for hiding this comment

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

Code Review

이번 PR은 텍스트 입력 필드의 최소 글자 수 유효성 검사 UX를 개선하는 변경 사항을 담고 있습니다. 기존에 버튼을 비활성화하던 방식에서, 유효하지 않은 입력 필드에 시각적 피드백(빨간 테두리)을 주고 에러 메시지를 표시하는 방식으로 변경되었습니다. forwardRef를 사용하여 부모 컴포넌트에서 TextArea에 접근하고 포커스를 제어할 수 있도록 한 점과, 에러 발생 시 해당 필드로 스크롤하는 기능은 사용자 경험을 크게 향상시킬 것입니다. 전반적으로 좋은 방향의 개선이지만, 유효성 검사 로직에 치명적인 버그가 있고, 에러 상태를 처리하는 부분에서 약간의 UX 지연 문제가 있어 몇 가지 수정을 제안합니다.

Comment on lines 56 to 84
const handleNext = () => {
if (!canGoNext) return;
if (!isContentValid) {
setContentError(true);

if (!isTitleValid) {
setTitleError(true);

// 스크롤 + 포커스
const el = titleRef.current;
if (el) {
scrollToCenter(el);
el.focus();
}
return;
}

// 스크롤 + 포커스
const el = contentRef.current;
if (el) {
scrollToCenter(el);
el.focus();
}
return;
}
setTitleError(false);
setContentError(false);
setPostInfo(titleText, contentText);
navigate("/photoFeed/lab/find");
};
Copy link
Contributor

Choose a reason for hiding this comment

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

critical

handleNext 함수의 유효성 검사 로직에 오류가 있습니다. isContentValid가 참이지만 isTitleValid가 거짓인 경우, 제목 필드에 대한 유효성 검사를 건너뛰고 폼이 제출됩니다. 이로 인해 유효하지 않은 제목으로 게시물이 생성될 수 있습니다. 두 필드를 각각 독립적으로 확인한 후 다음 단계로 진행하도록 로직을 수정해야 합니다.

  const handleNext = () => {
    const isTitleInvalid = !isTitleValid;
    const isContentInvalid = !isContentValid;

    setTitleError(isTitleInvalid);
    setContentError(isContentInvalid);

    if (isTitleInvalid) {
      const el = titleRef.current;
      if (el) {
        scrollToCenter(el);
        el.focus();
      }
      return;
    }

    if (isContentInvalid) {
      const el = contentRef.current;
      if (el) {
        scrollToCenter(el);
        el.focus();
      }
      return;
    }

    setPostInfo(titleText, contentText);
    navigate("/photoFeed/lab/find");
  };

Copy link
Contributor Author

Choose a reason for hiding this comment

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

첫번째 에러만 강조하는 로직으로 변경: 제목 체크 -> 내용 체크

Comment on lines +87 to +91
className={[
"flex flex-col gap-[0.625rem] rounded-2xl border bg-neutral-900 p-[1.25rem]",
isError ? "border-red-500" : "border-neutral-750",
className,
].join(" ")}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

[...].join(" ")을 사용하여 클래스 이름을 결합하는 방식은 불필요한 공백을 만들거나 falsy 값을 제대로 처리하지 못하는 등 오류가 발생하기 쉽습니다. 코드의 안정성과 가독성을 높이기 위해 clsxclassnames 같은 유틸리티 라이브러리를 사용하거나, 간단한 헬퍼 함수를 만들어 사용하는 것이 좋습니다.

Suggested change
className={[
"flex flex-col gap-[0.625rem] rounded-2xl border bg-neutral-900 p-[1.25rem]",
isError ? "border-red-500" : "border-neutral-750",
className,
].join(" ")}
className={[
"flex flex-col gap-[0.625rem] rounded-2xl border bg-neutral-900 p-[1.25rem]",
isError ? "border-red-500" : "border-neutral-750",
className,
].filter(Boolean).join(" ")}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

반영

Comment on lines +124 to +129
onChange={(v) => {
setTitleText(v);
if (titleError && isTitleValid) {
setTitleError(false);
}
}}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

에러 상태가 한 글자 입력이 늦게 해제되는 문제가 있습니다. isTitleValid는 비동기적으로 업데이트되는 titleText 상태에 의존하는 memoized 값이기 때문입니다. 더 나은 사용자 경험을 위해, onChange 핸들러 내에서 새로운 값으로 직접 유효성을 검사하여 즉시 에러 상태를 해제하는 것이 좋습니다.

            onChange={(v) => {
              setTitleText(v);
              if (titleError && isValidText(v, LIMITS.titleMin, LIMITS.titleMax)) {
                setTitleError(false);
              }
            }}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

반영

Comment on lines +150 to +155
onChange={(v) => {
setContentText(v);
if (contentError && isContentValid) {
setContentError(false);
}
}}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

제목 필드와 마찬가지로, 내용 필드의 에러 상태도 한 글자 늦게 해제됩니다. 사용자 경험을 개선하기 위해 onChange 핸들러 내에서 입력된 값으로 직접 유효성을 검사하여, 입력이 유효해지는 즉시 에러를 해제하도록 수정하는 것을 권장합니다.

            onChange={(v) => {
              setContentText(v);
              if (contentError && isValidText(v, LIMITS.contentMin, LIMITS.contentMax)) {
                setContentError(false);
              }
            }}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

반영

Comment on lines +113 to +118
onChange={(v) => {
setReviewText(v);
if (reviewTextError && canSave) {
setReviewTextError(false);
}
}}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

에러 상태가 늦게 해제되는 문제가 있습니다. canSave는 비동기적으로 업데이트되는 reviewText 상태에 의존하기 때문입니다. 입력이 유효해지는 즉시 에러를 해제하려면, onChange 핸들러 내에서 새로운 값으로 직접 유효성을 검사하는 것이 좋습니다.

Suggested change
onChange={(v) => {
setReviewText(v);
if (reviewTextError && canSave) {
setReviewTextError(false);
}
}}
onChange={(v) => {
setReviewText(v);
if (reviewTextError) {
const isValid = v.length >= MIN && v.length <= MAX;
if (isValid) {
setReviewTextError(false);
}
}
}}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

반영

Copy link
Contributor

@MlNTYS MlNTYS left a comment

Choose a reason for hiding this comment

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

PRAISE: 수고하셨습니다! 포뇨 귀엽네요..

Copy link
Contributor

@jeonbinggu jeonbinggu left a comment

Choose a reason for hiding this comment

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

PRAISE : 고생하셨습니다 최소 글자 표시로 인해서 UX 측면이 훨씬 좋아진 것 같습니다

@dodaaaaam dodaaaaam merged commit d40e87a into develop Feb 12, 2026
3 checks passed
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] 최소 글자 관련 수정

3 participants