Skip to content

Conversation

@toothlessdev
Copy link
Member

@toothlessdev toothlessdev commented Aug 27, 2025

✅ Linked Issue

🔍 What I did

  • 배너 클릭시 지원하기 페이지로 이동하도록 수정

Summary by CodeRabbit

  • New Features
    • Clicking the banner now navigates users to the application page (/apply).
  • Bug Fixes
    • Closing the banner no longer triggers unintended navigation.
  • Style
    • Banner shows a pointer cursor on hover to indicate it is clickable.

@toothlessdev toothlessdev self-assigned this Aug 27, 2025
@vercel
Copy link

vercel bot commented Aug 27, 2025

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

Project Deployment Preview Comments Updated (UTC)
mosu-client Ready Ready Preview Comment Aug 27, 2025 0:07am

@coderabbitai
Copy link

coderabbitai bot commented Aug 27, 2025

Walkthrough

Replaces the banner container with a Next.js Link (href="/apply") to make the banner clickable, adds a hover cursor pointer, and prevents the close button from triggering navigation by calling e.stopPropagation() before hideBanner().

Changes

Cohort / File(s) Summary
Banner interaction update
mosu-app/src/features/banner/ui/Banner.tsx
Wraps banner in Link (href="/apply") for navigation, adds hover:cursor-pointer, and calls e.stopPropagation() in the close button handler to prevent Link navigation. No public API changes.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant BannerUI as Banner (Link)
  participant NextLink as Next/Link
  participant ApplyPage as /apply

  rect rgba(200,240,255,0.25)
  note over User,BannerUI: Click banner area (Link)
  User->>BannerUI: Click
  BannerUI->>NextLink: native link navigation
  NextLink-->>ApplyPage: Navigate to /apply
  end

  User->>BannerUI: Click close (X)
  note over BannerUI: close handler calls e.stopPropagation()
  BannerUI->>BannerUI: hideBanner()
  BannerUI--x NextLink: Navigation prevented
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Assessment against linked issues

Objective Addressed Explanation
Banner click navigates to 신청하기 page (/apply) [#371]
Add Google Analytics event for navigation to each apply page [#371] No analytics/GA event call added in the click/navigation path.

Poem

I hop and click the shiny sign,
A Link whisks me to /apply in time.
The close button whispers, "not today,"
I hide the banner, then bound away. 🥕

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature#371

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.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

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

github-actions bot commented Aug 27, 2025

Messages
📖 ✅ PR 제목에 이슈 번호가 포함되어 있습니다.
📖 ✅ PR에 Reviewers가 지정되어 있습니다.
📖 ✅ PR에 라벨이 지정되어 있습니다.
📖 ✅ PR에 Assignees가 지정되어 있습니다.
📖 ✅ package.json에 변경사항이 없습니다.
📖 ✅ 브랜치 이름 'feature#371'이 컨벤션을 따릅니다.
📖 ✅ TypeScript 컴파일이 성공적으로 완료되었습니다.
📖 ✅ ESLint 검사 결과 문제가 없습니다.

📝 추가 및 변경된 파일

총 1개 파일 변경

└── 📂 mosu-app/
    └── 📂 src/
        └── 📂 features/
            └── 📂 banner/
                └── 📂 ui/
                    └── ⚛️ Banner.tsx

Generated by 🚫 dangerJS against 5cd3ac8

@toothlessdev toothlessdev requested a review from kimgho August 27, 2025 12:05
@sonarqubecloud
Copy link

@github-actions
Copy link

📚 Storybook이 Chromatic에 배포되었습니다!

Copy link

@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

Caution

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

⚠️ Outside diff range comments (1)
mosu-app/src/features/banner/ui/Banner.tsx (1)

56-57: Guard against SSR and missing portal target

document.getElementById(...) may be null or unavailable during SSR, causing createPortal to throw. Guard before calling.

Use this pattern:

// at top
import React from "react";

// inside component
const [mountNode, setMountNode] = React.useState<HTMLElement | null>(null);
React.useEffect(() => {
  setMountNode(document.getElementById(BANNER_PORTAL_ID) as HTMLElement | null);
}, []);

if (!isVisible || !mountNode) return null;

return createPortal(
  /* ...section... */,
  mountNode,
);
📜 Review details

Configuration used: CodeRabbit UI

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 d53742f and 47bdf1c.

📒 Files selected for processing (1)
  • mosu-app/src/features/banner/ui/Banner.tsx (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
mosu-app/src/features/banner/ui/Banner.tsx (1)
mosu-app/src/features/banner/contexts/BannerProvider.tsx (1)
  • useBannerVisibility (39-45)
⏰ 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: Run DangerJS
🔇 Additional comments (3)
mosu-app/src/features/banner/ui/Banner.tsx (3)

13-13: LGTM on router instantiation
No issues with const router = useRouter();.


47-50: Good use of stopPropagation on the close button

Prevents unintended navigation while closing. Looks correct.


3-3: No change needed: using Pages Router
Banner.tsx correctly imports useRouter from next/router. The repository has no app/ directory under mosu-app and all other routes (including src/pages/**) use next/router, confirming the Pages Router is in use. Resolving this comment.

@github-actions
Copy link

📚 Storybook이 Chromatic에 배포되었습니다!

Copy link

@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

♻️ Duplicate comments (1)
mosu-app/src/features/banner/ui/Banner.tsx (1)

3-3: LGTM: Using Next.js Link improves semantics and keyboard a11y

Replacing the clickable container with Link is the right move and addresses the earlier a11y concern.

📜 Review details

Configuration used: CodeRabbit UI

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 47bdf1c and 5cd3ac8.

📒 Files selected for processing (1)
  • mosu-app/src/features/banner/ui/Banner.tsx (3 hunks)
🔇 Additional comments (1)
mosu-app/src/features/banner/ui/Banner.tsx (1)

19-26: Add Google Analytics event to Banner’s apply link

Verified: there’s no existing analytics helper in the codebase, so using window.gtag directly is acceptable.

• File: mosu-app/src/features/banner/ui/Banner.tsx (around lines 19–26)
• Purpose: emit a “banner_click” GA event before client-side navigation to satisfy issue #371.

Apply this diff (note corrected Tailwind class from w/full to w-full):

--- a/mosu-app/src/features/banner/ui/Banner.tsx
+++ b/mosu-app/src/features/banner/ui/Banner.tsx
@@ -19,7 +19,12 @@
                 <Link
-                    className="relative flex w/full justify-start px-4 hover:cursor-pointer md:justify-center"
+                    className="relative flex w-full justify-start px-4 hover:cursor-pointer md:justify-center"
                     style={{
                         height: BANNER_HEIGHT,
                         background: "linear-gradient(to bottom, #1d1d1d28 0%, #ff1d3828 100%)",
                     }}
+                    onClick={() => {
+                        window.gtag?.("event", "banner_click", {
+                            event_category: "engagement",
+                            event_label: "apply",
+                            transport_type: "beacon",
+                        });
+                    }}
                     href="/apply"
                 >

Optional: If you encounter TypeScript errors about window.gtag, add a declaration (e.g., in global.d.ts):

declare global {
  interface Window {
    gtag?: (...args: any[]) => void;
  }
}

Comment on lines 43 to +53
<button
className="absolute right-2 block h-full hover:cursor-pointer md:right-5"
aria-label="배너 닫기"
onClick={hideBanner}
onClick={(e) => {
e.stopPropagation();
hideBanner();
}}
>
<X color="#fff" />
</button>
</div>
</Link>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

⚠️ Potential issue

Fix nested interactive control (button inside Link) and guard against accidental navigation

A button inside an anchor violates a11y (no-nested-interactive) and may still navigate despite stopPropagation. At minimum, prevent default; ideally, move the button outside Link and absolutely position it.

Minimal guard (within current structure):

-                    <button
+                    <button
+                        type="button"
                         className="absolute right-2 block h-full hover:cursor-pointer md:right-5"
                         aria-label="배너 닫기"
-                        onClick={(e) => {
-                            e.stopPropagation();
-                            hideBanner();
-                        }}
+                        onClick={(e) => {
+                            e.preventDefault();
+                            e.stopPropagation();
+                            hideBanner();
+                        }}
                     >

Preferred refactor (move button outside Link to avoid nested interactive):

-            <section className="w-full bg-black" style={{ height: BANNER_HEIGHT }}>
-                <Link
-                    className="relative flex w-full justify-start px-4 hover:cursor-pointer md:justify-center"
+            <section className="relative w-full bg-black" style={{ height: BANNER_HEIGHT }}>
+                <Link
+                    className="flex w-full justify-start px-4 hover:cursor-pointer md:justify-center"
                     style={{
                         height: BANNER_HEIGHT,
                         background: "linear-gradient(to bottom, #1d1d1d28 0%, #ff1d3828 100%)",
                     }}
                     href="/apply"
+                    onClick={() => {
+                        (window as any).gtag?.("event", "banner_click", {
+                            event_category: "engagement",
+                            event_label: "apply",
+                            transport_type: "beacon",
+                        });
+                    }}
                 >
                   ...
-                    <button
-                        className="absolute right-2 block h-full hover:cursor-pointer md:right-5"
-                        aria-label="배너 닫기"
-                        onClick={(e) => {
-                            e.stopPropagation();
-                            hideBanner();
-                        }}
-                    >
-                        <X color="#fff" />
-                    </button>
-                </Link>
+                </Link>
+                <button
+                    type="button"
+                    className="absolute inset-y-0 right-2 z-10 flex items-center hover:cursor-pointer md:right-5"
+                    aria-label="배너 닫기"
+                    onClick={() => hideBanner()}
+                >
+                    <X color="#fff" />
+                </button>
🤖 Prompt for AI Agents
In mosu-app/src/features/banner/ui/Banner.tsx around lines 43 to 53 there is a
button rendered inside a Link which creates a nested interactive control and can
still trigger navigation; fix it by either (preferred) moving the button outside
the Link and positioning it absolutely so it visually overlaps the banner while
the Link only wraps the non-interactive content, or (minimal) keep the button
inside but update its onClick to call e.preventDefault() and
e.stopPropagation(), then call hideBanner(), and ensure the button retains
aria-label and keyboard focusability; implement the preferred refactor where
possible to fully resolve the a11y violation.

Copy link
Contributor

@kimgho kimgho left a comment

Choose a reason for hiding this comment

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

고생하셨습니다 💯

@kimgho kimgho merged commit a4322ac into main Aug 27, 2025
13 checks passed
@kimgho kimgho deleted the feature#371 branch August 27, 2025 12:37
@github-project-automation github-project-automation bot moved this from 진행중 to 완료 in mosu-client Aug 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: 완료

Development

Successfully merging this pull request may close these issues.

[✍️ 기능 변경 요청] 모의수능 할인배너 상호작용 이벤트 추가

3 participants