Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions mosu-app/src/features/banner/ui/Banner.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { X } from "lucide-react";
import Image from "next/image";
import Link from "next/link";
import { createPortal } from "react-dom";

import imgDiscount from "@/features/banner/assets/img-discount.png";
Expand All @@ -15,12 +16,13 @@ export const Banner = () => {
isVisible &&
createPortal(
<section className="w-full bg-black" style={{ height: BANNER_HEIGHT }}>
<div
className="relative flex w-full justify-start px-4 md:justify-center"
<Link
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%)",
}}
href="/apply"
>
<div className="flex items-center justify-center">
<article>
Expand All @@ -41,11 +43,14 @@ export const Banner = () => {
<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>
Comment on lines 43 to +53
Copy link
Copy Markdown

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.

</section>,
document.getElementById(BANNER_PORTAL_ID) as HTMLElement,
)
Expand Down