Skip to content

[Fix/style] 파견학교 / 멘토페이지 / 토스트 디자인 반영#530

Open
enunsnv wants to merge 6 commits into
mainfrom
fix/style
Open

[Fix/style] 파견학교 / 멘토페이지 / 토스트 디자인 반영#530
enunsnv wants to merge 6 commits into
mainfrom
fix/style

Conversation

@enunsnv
Copy link
Copy Markdown
Contributor

@enunsnv enunsnv commented May 26, 2026

작업 내용

1. 파견학교 상세 페이지 좋아요 / 공유 버튼 디자인 수정 반영

After
스크린샷 2026-05-27 15 07 26
  • 공유 버튼 수정 완료
  • 좋아요 버튼이 디자인 수정 중에 있어, 완료 후 추가 수정 예정입니다!

2. 멘토 카드 아티클 추가

After
mentor-article-card
  • 멘토 카드 아티클 추가
  • 최신 아티클 1개만 노출되는 것을 확인

3. 토스트 디자인 수정

좋아요 버튼 누르는 경우 좋아요 버튼 해지하는 경우
like-toast unlike-toast

※ 디자인 시안에는 포함되어 있지 않아 임의로 추가하였습니다.
수정이 필요한 경우 말씀해주시면 반영하겠습니다.
공유 버튼 누르는 경우 심사 중인 성적을 눌렀을 때
share-toast pending-grade-toast
게시물 좋아요 누르는 경우 게시물 좋아요 해지하는 경우
post-like-toast post-unlike-toast

※ 디자인 시안에는 포함되어 있지 않아 임의로 추가하였습니다.
수정이 필요한 경우 말씀해주시면 반영하겠습니다.
불가능한 서비스를 눌렀을 때 승인 거절된 성적을 눌렀을 때
unavailable-service-toast 테스트 계정에 승인 거절된 성적 데이터가 없어

테스트하지 못했습니다 🥲

4. 새로운 아티클 추가 하기 아티클 섹션에서 가장 상단에 고정

After
image

특이 사항

3번 작업의 토스트 디자인을 전역으로 적용하였습니다. 솔커 로고로 통일하였으며, 추가적으로 수정 사항이 있다면 알려주세요🙂
또한 모든 토스트를 전부 다 확인해보지는 못 했기 때문에 혹시 적용 안된 곳이 있다면 알려주세요 !

질문 사항

리뷰 요구사항 (선택)

@enunsnv enunsnv requested review from manNomi and wibaek as code owners May 26, 2026 07:52
@vercel
Copy link
Copy Markdown

vercel Bot commented May 26, 2026

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

Project Deployment Actions Updated (UTC)
solid-connect-web-admin Ready Ready Preview, Comment May 27, 2026 8:49am
solid-connection-web Ready Ready Preview, Comment May 27, 2026 8:49am

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 26, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 6c30acd8-01bb-4257-9d90-1640b5fa0224

📥 Commits

Reviewing files that changed from the base of the PR and between 072042c and a7b2930.

📒 Files selected for processing (6)
  • apps/web/src/app/layout.tsx
  • apps/web/src/app/mentor/chat/[chatId]/_ui/ChatContent/index.tsx
  • apps/web/src/app/mentor/modify/_ui/ModifyContent/index.tsx
  • apps/web/src/app/my/_ui/MyProfileContent/index.tsx
  • apps/web/src/app/my/apply-mentor/_components/UniversityScreen/index.tsx
  • apps/web/src/app/my/apply-mentor/page.tsx
✅ Files skipped from review due to trivial changes (1)
  • apps/web/src/app/layout.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/web/src/app/my/apply-mentor/page.tsx
  • apps/web/src/app/my/apply-mentor/_components/UniversityScreen/index.tsx
  • apps/web/src/app/mentor/chat/[chatId]/_ui/ChatContent/index.tsx

Walkthrough

  1. 프로젝트 전반에서 react-hot-toast 호출을 showIconToast(icon, message)로 대체했습니다.
  2. showIconToast 유틸을 추가해 아이콘 매핑, 중복 방지, 노출/쿨다운 타이밍을 구현했습니다.
  3. 토스트 관련 SVG(토스트 아이콘)와 인덱스를 정리·추가했습니다.
  4. Toaster 위치(top)를 80 → 68로 조정했습니다.
  5. 대학 상세의 공유 버튼을 IconShare/IconShareFilled로 교체하고 클릭 시 600ms 토글 피드백을 추가했습니다.
  6. useGetArticleList 훅 시그니처를 확장해 options?.enabled로 쿼리 활성화 제어를 가능하게 했습니다.
  7. ArticlePreview 컴포넌트를 추가하고 MentorCard가 확장 시 최신 아티클을 불러와 미리보기를 렌더링하도록 했습니다.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • wibaek
  • manNomi

📋 전체 변경 사항

  1. 이 PR은 프로젝트 전반의 토스트 표시를 showIconToast로 통합하고, 토스트 아이콘 자산 추가 및 관련 호출을 교체합니다.
  2. 대학 상세 페이지의 공유 버튼을 새 아이콘으로 교체하고 클릭 시 600ms 시각적 피드백을 제공합니다.
  3. 아티클 관련으로 useGetArticleList의 활성화 옵션을 추가하고, ArticlePreview 컴포넌트를 도입해 MentorCard가 확장될 때 최신 아티클 미리보기를 표시합니다.

🚶 Walkthrough

  1. 토스트 유틸 추가 및 아이콘 정리

    • showIconToast 타입과 구현을 추가하고, 토스트용 SVG 인덱스를 정리·추가했습니다.
  2. 전역 및 컴포넌트 단위 호출 교체

    • 여러 API 훅과 페이지/컴포넌트에서 react-hot-toast 호출을 showIconToast로 교체했습니다.
    • react-query 전역 에러 처리와 여러 mutation/onSuccess 경로의 토스트 호출도 교체되었습니다.
  3. 대학 상세 공유 버튼 개선

    • IconShare와 IconShareFilled를 등록하고, UniversityBtns에서 복사 동작에 시각 피드백(600ms opacity 토글)을 추가했습니다.
  4. 아티클 기능 확장

    • useGetArticleList에 options?.enabled를 추가해 쿼리 활성화를 제어 가능하게 했고, ArticlePreview 컴포넌트를 만들어 MentorCard 확장 시 최신 아티클을 보여주도록 했습니다.

🎯 코드 리뷰 예상 난이도

🎯 3 (Moderate) | ⏱️ ~25 분

💭 제안 리뷰어

  • wibaek
  • manNomi
  • khwww
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning 설명에서 필수 섹션(작업 내용, 특이 사항)은 포함되었으나, '관련 이슈' 섹션이 누락되었습니다. PR 설명에 '## 관련 이슈' 섹션을 추가하고 관련 GitHub 이슈 번호(#번호)를 명시해주세요.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed 제목이 PR의 주요 변경사항(토스트 디자인 반영, 파견학교/멘토페이지 수정)을 명확하게 요약하고 있습니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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/style

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


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.

@enunsnv enunsnv changed the title [Fix/style] 수정 중 !!!!! [Fix/style] 수정 중 입니다 !!!!! May 26, 2026
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 (1)
apps/web/src/apis/news/getNewsList.ts (1)

20-20: 💤 Low value

타입 시그니처와 일치하도록 중복 체크를 제거하는 것이 좋겠습니다.

userId의 타입이 number로 선언되어 있어 null이 될 수 없으므로, userId !== null 체크는 중복입니다. 다음과 같이 간소화할 수 있습니다:

♻️ 제안하는 수정안
-    enabled: userId !== null && userId !== 0 && (options?.enabled ?? true),
+    enabled: userId !== 0 && (options?.enabled ?? true),
🤖 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 `@apps/web/src/apis/news/getNewsList.ts` at line 20, The enabled condition
includes a redundant null check for userId; since userId is typed as number
(non-nullable), remove the userId !== null clause and simplify the expression in
the enabled assignment (the property named enabled in
apps/web/src/apis/news/getNewsList.ts) to only check userId !== 0 &&
(options?.enabled ?? true).
🤖 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
`@apps/web/src/app/university/`[homeUniversity]/[id]/_ui/UniversityDetail/_ui/UniversityBtns.tsx:
- Around line 80-95: The share button lacks a visible keyboard focus indicator;
update the button element that uses onClick={handleCopy} and the
isShareActive/IconShare/IconShareFilled visuals to include the same focus ring
classes used by the like button (e.g., add focus:ring-2 focus:ring-white/50 and
remove or replace focus:outline-none) so keyboard users see a clear focus state
while preserving the current hover/active animations and icon opacity toggles.
- Around line 54-59: handleCopy currently calls
navigator.clipboard.writeText(...).then(() => {}) without error handling and
creates a potential memory leak by using setTimeout without cleanup; update
handleCopy to await or use .then/.catch on navigator.clipboard.writeText to show
a success toast on resolve and an error toast on reject (include clear
messaging), and replace the raw setTimeout with a tracked timeoutId (e.g., store
id in a ref or state) so you can call clearTimeout during unmount; add a
useEffect cleanup that clears the timeoutId and prevents calling
setIsShareActive on an unmounted component.

---

Nitpick comments:
In `@apps/web/src/apis/news/getNewsList.ts`:
- Line 20: The enabled condition includes a redundant null check for userId;
since userId is typed as number (non-nullable), remove the userId !== null
clause and simplify the expression in the enabled assignment (the property named
enabled in apps/web/src/apis/news/getNewsList.ts) to only check userId !== 0 &&
(options?.enabled ?? true).
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 9d0e914f-3443-4977-9d6b-efcf4c34a6ec

📥 Commits

Reviewing files that changed from the base of the PR and between 56daea0 and fec0a83.

⛔ Files ignored due to path filters (2)
  • apps/web/public/svgs/shareIcon.svg is excluded by !**/*.svg
  • apps/web/public/svgs/shareIconFilled.svg is excluded by !**/*.svg
📒 Files selected for processing (4)
  • apps/web/public/svgs/index.ts
  • apps/web/src/apis/news/getNewsList.ts
  • apps/web/src/app/university/[homeUniversity]/[id]/_ui/UniversityDetail/_ui/UniversityBtns.tsx
  • apps/web/src/components/mentor/MentorCard/_ui/ArticlePreview.tsx

Comment on lines 54 to 59
const handleCopy = () => {
navigator.clipboard.writeText(window.location.href).then(() => {});
toast.success("URL이 복사되었습니다.");
setIsShareActive(true);
setTimeout(() => setIsShareActive(false), 600);
};
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

공유 기능 구현에서 두 가지 개선이 필요합니다.

다음 사항들을 확인해 주세요:

  1. 클립보드 API 에러 처리 누락 (Line 55)

    • navigator.clipboard.writeText()의 빈 .then() 콜백이 불필요하며, 실패 시 처리를 위한 .catch() 핸들러가 없습니다.
    • 클립보드 API는 권한 문제나 브라우저 제약으로 실패할 수 있습니다.
  2. 메모리 누수 가능성 (Lines 57-58)

    • setTimeout이 정리(cleanup)되지 않아, 600ms 이내에 컴포넌트가 언마운트되면 언마운트된 컴포넌트에 상태 업데이트를 시도하게 됩니다.
    • React에서 흔히 발생하는 안티패턴입니다.
🔧 개선된 구현 제안
-  const handleCopy = () => {
-    navigator.clipboard.writeText(window.location.href).then(() => {});
-    toast.success("URL이 복사되었습니다.");
-    setIsShareActive(true);
-    setTimeout(() => setIsShareActive(false), 600);
-  };
+  const handleCopy = () => {
+    navigator.clipboard
+      .writeText(window.location.href)
+      .then(() => {
+        toast.success("URL이 복사되었습니다.");
+        setIsShareActive(true);
+      })
+      .catch(() => {
+        toast.error("URL 복사에 실패했습니다.");
+      });
+  };
+
+  useEffect(() => {
+    if (!isShareActive) return;
+    const timer = setTimeout(() => setIsShareActive(false), 600);
+    return () => clearTimeout(timer);
+  }, [isShareActive]);
🤖 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
`@apps/web/src/app/university/`[homeUniversity]/[id]/_ui/UniversityDetail/_ui/UniversityBtns.tsx
around lines 54 - 59, handleCopy currently calls
navigator.clipboard.writeText(...).then(() => {}) without error handling and
creates a potential memory leak by using setTimeout without cleanup; update
handleCopy to await or use .then/.catch on navigator.clipboard.writeText to show
a success toast on resolve and an error toast on reject (include clear
messaging), and replace the raw setTimeout with a tracked timeoutId (e.g., store
id in a ref or state) so you can call clearTimeout during unmount; add a
useEffect cleanup that clears the timeoutId and prevents calling
setIsShareActive on an unmounted component.

Comment on lines 80 to 95
<button
type="button"
onClick={handleCopy}
className={`/* stroke: #FFF; stroke-width: 1px; */ /* fill: linear-gradient(...) */ /* CSS의 fill은 SVG 속성이지만, 버튼 배경으로 적용합니다. */ /* backdrop-filter: blur(2px); */ /* filter: drop-shadow(...) */ /* 기타 스타일 */ rounded-full border border-white/80 bg-[linear-gradient(136deg,rgba(255,255,255,0.4)_14.87%,rgba(199,212,250,0.8)_89.1%)] p-3 drop-shadow-[2px_2px_6px_#C7D4FA] backdrop-blur-[2px] transition-transform duration-200 ease-in-out hover:scale-110 focus:outline-none focus:ring-2 focus:ring-white/50 active:scale-95`}
className="relative h-10 w-10 transition-transform duration-200 ease-in-out hover:scale-110 focus:outline-none active:scale-95"
>
{copyIcon}
<IconShare
width={40}
height={40}
className={`absolute inset-0 transition-opacity duration-300 ease-in-out ${isShareActive ? "opacity-0" : "opacity-100"}`}
/>
<IconShareFilled
width={40}
height={40}
className={`absolute inset-0 transition-opacity duration-300 ease-in-out ${isShareActive ? "opacity-100" : "opacity-0"}`}
/>
</button>
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

공유 버튼의 키보드 접근성 개선이 필요합니다.

아이콘 전환 애니메이션 구현은 깔끔하지만, 버튼에 포커스 인디케이터가 없어 키보드 네비게이션 사용자가 현재 포커스 위치를 파악하기 어렵습니다.

위의 좋아요 버튼(Line 76)에는 focus:ring-2 focus:ring-white/50이 있지만, 공유 버튼에는 focus:outline-none만 있고 대체 포커스 스타일이 없습니다.

♿ 접근성 개선 제안
       <button
         type="button"
         onClick={handleCopy}
-        className="relative h-10 w-10 transition-transform duration-200 ease-in-out hover:scale-110 focus:outline-none active:scale-95"
+        className="relative h-10 w-10 rounded-full transition-transform duration-200 ease-in-out hover:scale-110 focus:outline-none focus:ring-2 focus:ring-white/50 active:scale-95"
       >
📝 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
<button
type="button"
onClick={handleCopy}
className={`/* stroke: #FFF; stroke-width: 1px; */ /* fill: linear-gradient(...) */ /* CSS의 fill은 SVG 속성이지만, 버튼 배경으로 적용합니다. */ /* backdrop-filter: blur(2px); */ /* filter: drop-shadow(...) */ /* 기타 스타일 */ rounded-full border border-white/80 bg-[linear-gradient(136deg,rgba(255,255,255,0.4)_14.87%,rgba(199,212,250,0.8)_89.1%)] p-3 drop-shadow-[2px_2px_6px_#C7D4FA] backdrop-blur-[2px] transition-transform duration-200 ease-in-out hover:scale-110 focus:outline-none focus:ring-2 focus:ring-white/50 active:scale-95`}
className="relative h-10 w-10 transition-transform duration-200 ease-in-out hover:scale-110 focus:outline-none active:scale-95"
>
{copyIcon}
<IconShare
width={40}
height={40}
className={`absolute inset-0 transition-opacity duration-300 ease-in-out ${isShareActive ? "opacity-0" : "opacity-100"}`}
/>
<IconShareFilled
width={40}
height={40}
className={`absolute inset-0 transition-opacity duration-300 ease-in-out ${isShareActive ? "opacity-100" : "opacity-0"}`}
/>
</button>
<button
type="button"
onClick={handleCopy}
className="relative h-10 w-10 rounded-full transition-transform duration-200 ease-in-out hover:scale-110 focus:outline-none focus:ring-2 focus:ring-white/50 active:scale-95"
>
<IconShare
width={40}
height={40}
className={`absolute inset-0 transition-opacity duration-300 ease-in-out ${isShareActive ? "opacity-0" : "opacity-100"}`}
/>
<IconShareFilled
width={40}
height={40}
className={`absolute inset-0 transition-opacity duration-300 ease-in-out ${isShareActive ? "opacity-100" : "opacity-0"}`}
/>
</button>
🤖 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
`@apps/web/src/app/university/`[homeUniversity]/[id]/_ui/UniversityDetail/_ui/UniversityBtns.tsx
around lines 80 - 95, The share button lacks a visible keyboard focus indicator;
update the button element that uses onClick={handleCopy} and the
isShareActive/IconShare/IconShareFilled visuals to include the same focus ring
classes used by the like button (e.g., add focus:ring-2 focus:ring-white/50 and
remove or replace focus:outline-none) so keyboard users see a clear focus state
while preserving the current hover/active animations and icon opacity toggles.

@enunsnv enunsnv changed the title [Fix/style] 수정 중 입니다 !!!!! [Fix/style] 파견학교 / 멘토페이지 / 토스트 디자인 반영 May 27, 2026
@vercel vercel Bot temporarily deployed to Preview – solid-connect-web-admin May 27, 2026 07:54 Inactive
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 072042c070

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".


toast.custom(
() => (
<div className="animate-fadeIn pointer-events-auto flex h-[62px] w-[350px] items-center justify-center gap-2.5 rounded-[12px] bg-white px-5 py-4 shadow-[0px_4px_40px_0px_rgba(0,0,0,0.25)]">
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Let icon toasts grow for long messages

When callers pass a long message, this fixed h-[62px] w-[350px] container has no wrapping or word-break guard, so text can spill out of the white toast card instead of remaining readable. This now affects existing paths that pass long strings through showIconToast, such as SurveyModal including the full survey URL on popup-block errors and global API error messages; use a min-height/auto height and a max-width/break-words style instead of a fixed-height box.

Useful? React with 👍 / 👎.

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: 1

Caution

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

⚠️ Outside diff range comments (1)
apps/web/src/app/university/score/ScoreCard.tsx (1)

36-44: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

REJECTED 상태 배지 클릭 시 중복 토스트 발생 가능성

현재 구조에서는:

  1. REJECTED 배지 자체에 onClick 핸들러가 있어 거절 사유 토스트를 표시
  2. ScoreScreen.tsx에서 이 카드 전체를 <button>으로 감싸고 handleScoreClick을 연결

배지를 클릭하면 이벤트 버블링으로 인해 두 토스트가 연속으로 표시될 수 있습니다.

제안: 이벤트 버블링 방지
         <div
           className="flex h-5 cursor-pointer items-center gap-0.5 rounded-[20px] bg-accent-custom-red-light p-2.5"
-          onClick={() => showIconToast("logo", rejectedReason ?? "승인이 거절되었습니다.")}
+          onClick={(e) => {
+            e.stopPropagation();
+            showIconToast("logo", rejectedReason ?? "승인이 거절되었습니다.");
+          }}
         >
🤖 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 `@apps/web/src/app/university/score/ScoreCard.tsx` around lines 36 - 44, The
REJECTED badge's onClick in ScoreCard.tsx currently calls showIconToast(...) but
doesn't stop event propagation, causing ScoreScreen.tsx's parent <button> with
handleScoreClick to also fire and produce duplicate toasts; update the badge's
onClick handler to accept the click event, call event.stopPropagation(), then
call showIconToast(rejectedReason ?? "승인이 거절되었습니다.") so the badge toast shows
without triggering handleScoreClick in the parent.
🧹 Nitpick comments (2)
apps/web/src/app/university/score/ScoreScreen.tsx (1)

20-28: ⚡ Quick win

APPROVED 상태 클릭에 대한 사용자 피드백 누락

handleScoreClick이 REJECTED와 PENDING 상태에는 토스트를 표시하지만, APPROVED 상태의 성적을 클릭했을 때는 아무 피드백이 없습니다. 사용자 입장에서는 클릭이 동작하지 않는 것처럼 느껴질 수 있습니다.

제안: APPROVED 상태에 대한 안내 추가 또는 버튼 비활성화

옵션 1: APPROVED에도 안내 토스트 추가

   const handleScoreClick = (status: ScoreSubmitStatus) => {
     if (status === ScoreSubmitStatus.REJECTED) {
       showIconToast("cap", "승인거절된 성적은 사용할 수 없습니다");
       return;
     }
     if (status === ScoreSubmitStatus.PENDING) {
       showIconToast("cap", "심사중인 성적은 사용할 수 없습니다");
+      return;
     }
+    // APPROVED 상태는 이미 선택되어 있음을 안내
+    showIconToast("cap", "이미 사용 중인 성적입니다");
   };

옵션 2: APPROVED 카드는 버튼으로 감싸지 않기
렌더링 시 조건부로 버튼 래퍼 적용

🤖 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 `@apps/web/src/app/university/score/ScoreScreen.tsx` around lines 20 - 28,
handleScoreClick currently only handles REJECTED and PENDING so clicking an
APPROVED score gives no feedback; update the click behavior by adding handling
for ScoreSubmitStatus.APPROVED (e.g., call showIconToast with a helpful message
like "이미 승인된 성적입니다") or remove the clickable wrapper for APPROVED items instead.
Modify handleScoreClick to include an APPROVED branch (referencing
ScoreSubmitStatus and showIconToast) or change the render logic that wraps the
card/button so it conditionally applies the click handler only when status !==
ScoreSubmitStatus.APPROVED (locate the component that renders the clickable card
and the handleScoreClick usage).
apps/web/src/components/mentor/MentorCard/index.tsx (1)

111-117: 💤 Low value

아티클 로딩 상태에 대한 피드백 부재

현재 구현은 아티클이 로드되는 동안 아무것도 표시하지 않습니다. 카드를 확장할 때 아티클 API 호출이 진행 중이면 사용자는 아티클 섹션이 나타나기까지 빈 공간을 보게 됩니다.

제안: 로딩 상태 표시 추가
+         const { data: articles, isLoading: isLoadingArticles } = useGetArticleList(id ?? 0, { enabled: isExpanded && !!id });

          {/* 멘토 아티클 */}
-         {latestArticle && (
+         {(latestArticle || (isExpanded && isLoadingArticles)) && (
            <div className="mb-4">
              <h4 className="mb-2 text-blue-600 typo-sb-5">멘토 아티클</h4>
-             <ArticlePreview article={latestArticle} />
+             {isLoadingArticles ? (
+               <div className="text-k-400 typo-regular-4">아티클을 불러오는 중...</div>
+             ) : latestArticle ? (
+               <ArticlePreview article={latestArticle} />
+             ) : null}
            </div>
          )}
🤖 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 `@apps/web/src/components/mentor/MentorCard/index.tsx` around lines 111 - 117,
The MentorCard renders nothing while the article API is loading (only checks
latestArticle), causing blank space; add an explicit loading state (e.g.,
isLoadingArticle) used alongside latestArticle so the render shows a loading
indicator or skeleton where ArticlePreview would be while the fetch is in
progress, set isLoadingArticle=true before the API call that populates
latestArticle and false on success/error, and update the JSX around
latestArticle/ArticlePreview to render spinner/skeleton when isLoadingArticle is
true and ArticlePreview only when latestArticle is available.
🤖 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 `@apps/web/src/app/university/score/ScoreScreen.tsx`:
- Around line 47-65: The ScoreCard is wrapped in an interactive <button> while
the REJECTED badge inside ScoreCard also has its own click handler, causing
nested interactive elements and double toasts; fix by removing the external
<button> wrapper and either (A) make the whole card clickable by passing an
onClick prop from where ScoreCard is used (e.g., pass onClick={() =>
handleScoreClick(score.verifyStatus)} into ScoreCard and remove the badge's
internal onClick), or (B) keep the badge interactive and render the outer
container as a non-interactive element (div) with proper keyboard handling/role
if needed; apply the same change for the other occurrence around lines
referenced (70-85). Ensure you update ScoreCard props and its internal badge
handler accordingly (remove or conditionally disable badge onClick when
card-level onClick is provided).

---

Outside diff comments:
In `@apps/web/src/app/university/score/ScoreCard.tsx`:
- Around line 36-44: The REJECTED badge's onClick in ScoreCard.tsx currently
calls showIconToast(...) but doesn't stop event propagation, causing
ScoreScreen.tsx's parent <button> with handleScoreClick to also fire and produce
duplicate toasts; update the badge's onClick handler to accept the click event,
call event.stopPropagation(), then call showIconToast(rejectedReason ?? "승인이
거절되었습니다.") so the badge toast shows without triggering handleScoreClick in the
parent.

---

Nitpick comments:
In `@apps/web/src/app/university/score/ScoreScreen.tsx`:
- Around line 20-28: handleScoreClick currently only handles REJECTED and
PENDING so clicking an APPROVED score gives no feedback; update the click
behavior by adding handling for ScoreSubmitStatus.APPROVED (e.g., call
showIconToast with a helpful message like "이미 승인된 성적입니다") or remove the
clickable wrapper for APPROVED items instead. Modify handleScoreClick to include
an APPROVED branch (referencing ScoreSubmitStatus and showIconToast) or change
the render logic that wraps the card/button so it conditionally applies the
click handler only when status !== ScoreSubmitStatus.APPROVED (locate the
component that renders the clickable card and the handleScoreClick usage).

In `@apps/web/src/components/mentor/MentorCard/index.tsx`:
- Around line 111-117: The MentorCard renders nothing while the article API is
loading (only checks latestArticle), causing blank space; add an explicit
loading state (e.g., isLoadingArticle) used alongside latestArticle so the
render shows a loading indicator or skeleton where ArticlePreview would be while
the fetch is in progress, set isLoadingArticle=true before the API call that
populates latestArticle and false on success/error, and update the JSX around
latestArticle/ArticlePreview to render spinner/skeleton when isLoadingArticle is
true and ArticlePreview only when latestArticle is available.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: dfb9e483-7ca2-4d20-89ff-11e721737210

📥 Commits

Reviewing files that changed from the base of the PR and between fec0a83 and 072042c.

⛔ Files ignored due to path filters (5)
  • apps/web/public/svgs/toast/cap.svg is excluded by !**/*.svg
  • apps/web/public/svgs/toast/like.svg is excluded by !**/*.svg
  • apps/web/public/svgs/toast/link.svg is excluded by !**/*.svg
  • apps/web/public/svgs/toast/logo.svg is excluded by !**/*.svg
  • apps/web/public/svgs/toast/univ.svg is excluded by !**/*.svg
📒 Files selected for processing (45)
  • apps/web/public/svgs/toast/index.ts
  • apps/web/src/apis/Auth/postAppleAuth.ts
  • apps/web/src/apis/Auth/postEmailLogin.ts
  • apps/web/src/apis/Auth/postKakaoAuth.ts
  • apps/web/src/apis/MyPage/patchPassword.ts
  • apps/web/src/apis/MyPage/patchProfile.ts
  • apps/web/src/apis/Scores/postCreateGpa.ts
  • apps/web/src/apis/Scores/postCreateLanguageTest.ts
  • apps/web/src/apis/community/deleteComment.ts
  • apps/web/src/apis/community/deletePost.ts
  • apps/web/src/apis/community/patchUpdatePost.ts
  • apps/web/src/apis/community/postCreateComment.ts
  • apps/web/src/apis/community/postCreatePost.ts
  • apps/web/src/apis/reports/postReport.ts
  • apps/web/src/app/(home)/_ui/FindLastYearScoreBar/index.tsx
  • apps/web/src/app/community/[boardCode]/[postId]/Content.tsx
  • apps/web/src/app/community/[boardCode]/[postId]/KebabMenu.tsx
  • apps/web/src/app/community/[boardCode]/[postId]/modify/PostModifyForm.tsx
  • apps/web/src/app/community/[boardCode]/create/PostForm.tsx
  • apps/web/src/app/community/_hooks/useCommunityImageUpload.ts
  • apps/web/src/app/layout.tsx
  • apps/web/src/app/mentor/chat/[chatId]/_ui/ChatContent/index.tsx
  • apps/web/src/app/my/_ui/MyProfileContent/index.tsx
  • apps/web/src/app/my/apply-mentor/_components/UniversityScreen/index.tsx
  • apps/web/src/app/my/apply-mentor/page.tsx
  • apps/web/src/app/my/favorite/_ui/FavoriteContent/_hooks/useSelectUniversities.ts
  • apps/web/src/app/sign-up/email/EmailSignUpForm.tsx
  • apps/web/src/app/university/[homeUniversity]/[id]/_ui/UniversityDetail/_ui/UniversityBtns.tsx
  • apps/web/src/app/university/application/apply/ApplyPageContent.tsx
  • apps/web/src/app/university/application/apply/GpaStep.tsx
  • apps/web/src/app/university/application/apply/LanguageStep.tsx
  • apps/web/src/app/university/score/ScoreCard.tsx
  • apps/web/src/app/university/score/ScoreScreen.tsx
  • apps/web/src/components/layout/GlobalLayout/ui/AIInspectorFab/index.tsx
  • apps/web/src/components/login/signup/SignupPrepareScreen.tsx
  • apps/web/src/components/login/signup/SignupProfileScreen.tsx
  • apps/web/src/components/login/signup/SignupRegionScreen.tsx
  • apps/web/src/components/login/signup/SignupSurvey.tsx
  • apps/web/src/components/mentor/MentorCard/index.tsx
  • apps/web/src/components/modal/SurveyModal.tsx
  • apps/web/src/lib/react-query/queryClient.ts
  • apps/web/src/lib/toast/options.ts
  • apps/web/src/lib/toast/showIconToast.tsx
  • apps/web/src/utils/authUtils.ts
  • apps/web/src/utils/axiosInstance.ts
💤 Files with no reviewable changes (1)
  • apps/web/src/lib/toast/options.ts
✅ Files skipped from review due to trivial changes (9)
  • apps/web/public/svgs/toast/index.ts
  • apps/web/src/apis/reports/postReport.ts
  • apps/web/src/apis/MyPage/patchProfile.ts
  • apps/web/src/apis/Scores/postCreateLanguageTest.ts
  • apps/web/src/lib/toast/showIconToast.tsx
  • apps/web/src/components/login/signup/SignupSurvey.tsx
  • apps/web/src/apis/MyPage/patchPassword.ts
  • apps/web/src/components/modal/SurveyModal.tsx
  • apps/web/src/apis/Auth/postAppleAuth.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/src/app/university/[homeUniversity]/[id]/_ui/UniversityDetail/_ui/UniversityBtns.tsx

Comment on lines +47 to +65
<button
key={score.id}
name={languageTestMapping[score.languageTestResponse.languageTestType]}
score={formatLanguageTestScore(
score.languageTestResponse.languageTestType,
score.languageTestResponse.languageTestScore,
)}
status={score.verifyStatus}
// date={new Date(score.issueDate).toISOString()}
date="2026-01-01"
isFocused={score.verifyStatus === "APPROVED"}
rejectedReason={score.rejectedReason}
/>
type="button"
className="text-left"
onClick={() => handleScoreClick(score.verifyStatus)}
>
<ScoreCard
name={languageTestMapping[score.languageTestResponse.languageTestType]}
score={formatLanguageTestScore(
score.languageTestResponse.languageTestType,
score.languageTestResponse.languageTestScore,
)}
status={score.verifyStatus}
// date={new Date(score.issueDate).toISOString()}
date="2026-01-01"
isFocused={score.verifyStatus === "APPROVED"}
rejectedReason={score.rejectedReason}
/>
</button>
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

버튼으로 감싼 ScoreCard 내부에 클릭 가능한 배지 포함

ScoreCard<button>으로 감싸면서 접근성 문제가 발생합니다:

  1. ScoreCard의 REJECTED 배지도 클릭 가능한 요소(onClick 핸들러 포함)
  2. 이는 중첩된 인터랙티브 요소를 만들어 스크린 리더 사용자에게 혼란을 줄 수 있습니다
  3. REJECTED 배지 클릭 시 이벤트 버블링으로 인해 두 개의 토스트가 표시될 수 있습니다

더 나은 접근 방식:

  • ScoreCard를 버튼으로 감싸지 않고, 카드 내부의 배지에만 onClick 유지
  • 또는 카드 전체를 클릭 가능하게 만들고 배지의 개별 onClick 제거

Also applies to: 70-85

🤖 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 `@apps/web/src/app/university/score/ScoreScreen.tsx` around lines 47 - 65, The
ScoreCard is wrapped in an interactive <button> while the REJECTED badge inside
ScoreCard also has its own click handler, causing nested interactive elements
and double toasts; fix by removing the external <button> wrapper and either (A)
make the whole card clickable by passing an onClick prop from where ScoreCard is
used (e.g., pass onClick={() => handleScoreClick(score.verifyStatus)} into
ScoreCard and remove the badge's internal onClick), or (B) keep the badge
interactive and render the outer container as a non-interactive element (div)
with proper keyboard handling/role if needed; apply the same change for the
other occurrence around lines referenced (70-85). Ensure you update ScoreCard
props and its internal badge handler accordingly (remove or conditionally
disable badge onClick when card-level onClick is provided).

@manNomi
Copy link
Copy Markdown
Contributor

manNomi commented May 27, 2026

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a7b29305ca

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


const isDetail = mentor && "passTip" in mentor;

const { data: articles } = useGetArticleList(id ?? 0, { enabled: isExpanded && !!id });
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid fetching articles with chat room IDs

When this shared card is used in apps/web/src/app/my/match/_ui/MatchContent/index.tsx, the mentor prop is synthesized with id: room.id because the chat-room API does not provide a mentor id. After this change, expanding that matched-mentor card calls the news query with the chat room id (/news?author-id=<room.id>), which can either show an unrelated author's latest article or surface an error toast instead of the matched mentor's article. Gate this fetch to real mentor records or pass a separate author/mentor id for article lookup.

Useful? React with 👍 / 👎.

@manNomi
Copy link
Copy Markdown
Contributor

manNomi commented May 27, 2026

@enunsnv 님 코드래빗이랑 코덱스 리뷰만 반영해주시고 머지 가시죵 !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants