Skip to content
Merged
Show file tree
Hide file tree
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
2 changes: 1 addition & 1 deletion src/components/landing/CTASection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ function CTASection({ className }: { className?: string }) {
<div className="flex gap-3">
<InquiryDialog>
<button className="typo-button1 flex-1 rounded-md bg-[#00C8AA] px-400 py-300 text-white hover:bg-[#00877a]">
사전 예약하기
가입 문의하기
</button>
</InquiryDialog>
</div>
Expand Down
26 changes: 15 additions & 11 deletions src/components/landing/InquiryDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,29 @@ import { toastSuccess, toastError } from '@/stores/useToastStore';
import Image from 'next/image';

interface InquiryDialogProps {
children: ReactNode;
children?: ReactNode;
open?: boolean;
onOpenChange?: (open: boolean) => void;
}

function InquiryDialog({ children }: InquiryDialogProps) {
const [open, setOpen] = useState(false);
function InquiryDialog({ children, open, onOpenChange }: InquiryDialogProps) {
const [internalOpen, setInternalOpen] = useState(false);
const [email, setEmail] = useState('');
const [message, setMessage] = useState('');
const [isSubmitting, setIsSubmitting] = useState(false);
const dialogOpen = open ?? internalOpen;
const setDialogOpen = onOpenChange ?? setInternalOpen;

const handleClose = () => {
if (isSubmitting) return;
setOpen(false);
setDialogOpen(false);
setEmail('');
setMessage('');
};

const handleOpenChange = (next: boolean) => {
if (!next) handleClose();
else setOpen(true);
else setDialogOpen(true);
};

const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
Expand All @@ -56,8 +60,8 @@ function InquiryDialog({ children }: InquiryDialogProps) {
};

return (
<Dialog open={open} onOpenChange={handleOpenChange}>
<DialogTrigger asChild>{children}</DialogTrigger>
<Dialog open={dialogOpen} onOpenChange={handleOpenChange}>
{children && <DialogTrigger asChild>{children}</DialogTrigger>}
<DialogContent
showCloseButton={false}
className="flex w-[640px] flex-col bg-[#F3F5F7]"
Expand All @@ -66,12 +70,12 @@ function InquiryDialog({ children }: InquiryDialogProps) {
>
<DialogHeader
icon={<Image src={TimeIcon} width={24} height={24} alt="정보 아이콘" />}
title={<span className="typo-h2 text-black">사전예약</span>}
title={<span className="typo-h2 text-black">가입 문의</span>}
description={
<span className="typo-body2 text-[#909599]">
Weeth가 출시되면 메일로 가장 먼저 알려드릴게요!
Weeth 도입이 궁금하신가요?
<br />
추가 문의사항을 작성해 주시면 빠른 시일 내로 답변드리겠습니다.
가입 문의를 남겨주시면 안내해드릴게요.
</span>
}
showClose
Expand Down Expand Up @@ -129,7 +133,7 @@ function InquiryDialog({ children }: InquiryDialogProps) {
className="typo-button1 flex-1 rounded-md bg-[#00C8AA] px-400 py-300 text-white hover:bg-[#00877a]"
disabled={isSubmitting}
>
사전예약 완료
가입 문의
</button>
</div>
</DialogFooter>
Expand Down
2 changes: 1 addition & 1 deletion src/components/landing/heroSection.shared.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ function HeroSectionCTA() {
<div className="flex gap-3">
<InquiryDialog>
<Button className="block w-fit rounded-md bg-[#00C8AA] px-400 py-300 text-[16px] leading-[24px] font-semibold tracking-[-0.005em] text-white hover:bg-[#00877a]">
사전 예약하기
가입 문의하기
</Button>
</InquiryDialog>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/components/layout/header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ export default function Header({ isMain = true }: HeaderProps) {
href="#"
className="typo-button1 text-text-alternative hover:text-text-normal transition-colors"
>
사전예약
가입문의
</Link>
</>
)}
Expand Down
198 changes: 153 additions & 45 deletions src/components/layout/header/PublicHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,106 @@ import { useEffect, useRef, useState } from 'react';
import Image from 'next/image';
import Link from 'next/link';
import { motion } from 'framer-motion';
import { LogoIcon } from '@/assets/icons';
import { buttonVariants } from '@/components/ui';
import { DeleteIcon, LogoIcon, MenuIcon } from '@/assets/icons';
import {
buttonVariants,
Icon,
Sheet,
SheetClose,
SheetContent,
SheetTrigger,
} from '@/components/ui';
import { cn } from '@/lib/cn';
import { NAV_ITEMS } from '@/constants/landing/landing';
import { InquiryDialog } from '@/components/landing/InquiryDialog';

interface PublicHeaderProps {
className?: string;
showAuthButtons?: boolean;
}

function PublicMobileMenu({ showAuthButtons }: { showAuthButtons: boolean }) {
const [inquiryOpen, setInquiryOpen] = useState(false);

return (
<>
<InquiryDialog open={inquiryOpen} onOpenChange={setInquiryOpen} />
<Sheet>
<SheetTrigger asChild>
<button
type="button"
aria-label="메뉴 열기"
className="flex cursor-pointer items-center justify-center rounded-sm outline-none"
>
<Icon src={MenuIcon} alt="menu" size={40} className="text-icon-normal p-2" />
</button>
</SheetTrigger>
<SheetContent
side="right"
overlayClassName="bg-transparent"
className="data-[state=closed]:slide-out-to-right-0 data-[state=open]:slide-in-from-right-0 top-0 h-dvh w-full max-w-none bg-white shadow-none duration-0 data-[state=closed]:animate-none data-[state=open]:animate-none"
>
Comment thread
woneeeee marked this conversation as resolved.
<div className="flex items-center justify-between px-450 py-3">
<SheetClose asChild>
<Link href="/landing" aria-label="홈으로 이동">
<Image
src={LogoIcon}
alt="Weeth-logo"
width={90}
height={40}
className="h-[40px] w-[90px]"
/>
</Link>
</SheetClose>
<SheetClose asChild>
<button
type="button"
aria-label="메뉴 닫기"
className="flex cursor-pointer items-center justify-center rounded-sm outline-none"
>
<Icon src={DeleteIcon} alt="close" size={40} className="text-icon-normal p-2" />
</button>
</SheetClose>
</div>

<nav className="flex flex-col items-start gap-200 px-450 py-400" aria-label="랜딩 메뉴">
<SheetClose asChild>
<button
type="button"
className="cursor-pointer py-300 text-[24px] leading-[30px] font-bold tracking-[-0.005em]"
onClick={() => setInquiryOpen(true)}
>
가입문의
</button>
</SheetClose>

{showAuthButtons && (
<>
<SheetClose asChild>
<Link
href="/login"
className="cursor-pointer py-300 text-[24px] leading-[30px] font-bold tracking-[-0.005em]"
>
로그인
</Link>
</SheetClose>
<SheetClose asChild>
<Link
href="/login?intent=create"
className="cursor-pointer py-300 text-[24px] leading-[30px] font-bold tracking-[-0.005em]"
>
지금 무료로 시작하기
Comment thread
woneeeee marked this conversation as resolved.
</Link>
</SheetClose>
</>
)}
</nav>
Comment on lines +69 to +100
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 | 🟠 Major | ⚡ Quick win

모바일 메뉴에서 NAV_ITEMS가 빠져 있습니다.

현재 모바일 메뉴는 가입문의와 인증 액션만 렌더링하고, 데스크톱에서 노출하는 랜딩 섹션 링크들은 전혀 보여주지 않습니다. 이 상태면 작은 화면에서는 주요 섹션으로 이동할 수 없어서 헤더 기능이 축소됩니다. 데스크톱과 동일하게 NAV_ITEMS.map(...)을 사용하고, contact만 예외 처리해서 다이얼로그를 여는 쪽이 안전합니다.

가능한 수정 예시
-          <nav className="flex flex-col items-start gap-200 px-450 py-400" aria-label="랜딩 메뉴">
-            <SheetClose asChild>
-              <button
-                type="button"
-                className="cursor-pointer py-300 text-[24px] leading-[30px] font-bold tracking-[-0.005em]"
-                onClick={() => setInquiryOpen(true)}
-              >
-                가입문의
-              </button>
-            </SheetClose>
+          <nav className="flex flex-col items-start gap-200 px-450 py-400" aria-label="랜딩 메뉴">
+            {NAV_ITEMS.map(({ id, label, href }) =>
+              id === 'contact' ? (
+                <SheetClose key={id} asChild>
+                  <button
+                    type="button"
+                    className="cursor-pointer py-300 text-[24px] leading-[30px] font-bold tracking-[-0.005em]"
+                    onClick={() => setInquiryOpen(true)}
+                  >
+                    {label}
+                  </button>
+                </SheetClose>
+              ) : (
+                <SheetClose key={id} asChild>
+                  <Link
+                    href={href}
+                    className="cursor-pointer py-300 text-[24px] leading-[30px] font-bold tracking-[-0.005em]"
+                  >
+                    {label}
+                  </Link>
+                </SheetClose>
+              ),
+            )}
 
             {showAuthButtons && (
               <>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/layout/header/PublicHeader.tsx` around lines 69 - 100, The
mobile nav is missing the NAV_ITEMS links; update the nav in PublicHeader to
iterate NAV_ITEMS.map and render each item similarly to desktop, using
SheetClose asChild and Link for normal items and treating the item with id ===
'contact' specially by rendering a button that calls setInquiryOpen(true); keep
existing showAuthButtons handling intact and preserve the same className/text
styles used for other nav entries so mobile shows the same landing section links
as desktop.

</SheetContent>
</Sheet>
</>
);
}

export default function PublicHeader({ className, showAuthButtons = true }: PublicHeaderProps) {
const [visible, setVisible] = useState(true);
const lastScrollY = useRef(0);
Expand Down Expand Up @@ -41,12 +131,12 @@ export default function PublicHeader({ className, showAuthButtons = true }: Publ
animate={{ y: visible ? 0 : -80, opacity: visible ? 1 : 0 }}
transition={{ duration: 0.25, ease: 'easeInOut' }}
className={cn(
'fixed top-0 left-0 z-1 flex w-full items-center justify-between bg-[#F3F5F7] px-450 py-300',
'fixed top-0 left-0 z-1 w-full bg-[#F3F5F7]',
!visible && 'pointer-events-none',
className,
)}
>
<div className="flex items-center gap-300">
<div className="tablet:hidden flex items-center justify-between bg-[#F3F5F7] px-450 py-3">
<Link href="/landing" aria-label="홈으로 이동">
<Image
src={LogoIcon}
Expand All @@ -59,51 +149,69 @@ export default function PublicHeader({ className, showAuthButtons = true }: Publ
}}
/>
</Link>
<nav className="flex items-center gap-300">
{NAV_ITEMS.map(({ id, label, href }) =>
id === 'contact' ? (
<InquiryDialog key={id}>
<button
type="button"
className="typo-button1 cursor-pointer whitespace-nowrap text-[#909599] transition-colors hover:text-black"
>
{label}
</button>
</InquiryDialog>
) : (
<Link
key={id}
href={href}
className="typo-button1 whitespace-nowrap text-[#909599] transition-colors hover:text-black"
>
{label}
</Link>
),
)}
</nav>
<PublicMobileMenu showAuthButtons={showAuthButtons} />
</div>
{showAuthButtons && (
<div className="flex items-center gap-200">
<Link
href="/login"
className={cn(
buttonVariants({ variant: 'secondary', size: 'md' }),
'bg-[#E6EAED] whitespace-nowrap text-black',
)}
>
로그인

<div className="tablet:flex hidden w-full items-center justify-between px-450 py-300">
<div className="flex items-center gap-300">
<Link href="/landing" aria-label="홈으로 이동">
<Image
src={LogoIcon}
alt="Weeth-logo"
width={90}
height={40}
className="h-[40px] w-[90px]"
onClick={() => {
window.scrollTo({ top: 0, behavior: 'smooth' });
}}
/>
</Link>
<Link
href="/login?intent=create"
className={cn(
buttonVariants({ variant: 'primary', size: 'md' }),
'bg-[#00C8AA] whitespace-nowrap text-white',
<nav className="flex items-center gap-300">
{NAV_ITEMS.map(({ id, label, href }) =>
id === 'contact' ? (
<InquiryDialog key={id}>
<button
type="button"
className="typo-button1 cursor-pointer whitespace-nowrap text-[#909599] transition-colors hover:text-black"
>
{label}
</button>
</InquiryDialog>
) : (
<Link
key={id}
href={href}
className="typo-button1 whitespace-nowrap text-[#909599] transition-colors hover:text-black"
>
{label}
</Link>
),
)}
>
지금 무료로 시작하기
</Link>
</nav>
</div>
)}
{showAuthButtons && (
<div className="flex items-center gap-200">
<Link
href="/login"
className={cn(
buttonVariants({ variant: 'secondary', size: 'md' }),
'bg-[#E6EAED] whitespace-nowrap text-black',
)}
>
로그인
</Link>
<Link
href="/login?intent=create"
className={cn(
buttonVariants({ variant: 'primary', size: 'md' }),
'bg-[#00C8AA] whitespace-nowrap text-white',
)}
>
지금 무료로 시작하기
</Link>
</div>
)}
</div>
</motion.header>
);
}
Expand Down
2 changes: 1 addition & 1 deletion src/constants/landing/landing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,5 +111,5 @@ export const FOOTER_MENUS = [

export const NAV_ITEMS = [
// { id: 'service', label: '서비스 소개', href: '#service' },
{ id: 'contact', label: '사전예약', href: '#contact' },
{ id: 'contact', label: '가입문의', href: '#contact' },
];
Loading