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: 2 additions & 0 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { dehydrate, QueryClient } from "@tanstack/react-query";
import type { Metadata } from "next";

import Toast from "@/components/common/toast/index";
import TutorialContainer from "@/components/common/tutorial/_components/tutorial-container";
import MainContent from "@/components/main-content";
import NavBar from "@/components/nav-bar";
import AuthInitializer from "@/provider/AuthInitializer";
Expand Down Expand Up @@ -52,6 +53,7 @@ export default async function RootLayout({
<AuthRefreshHandler />
<NavBar />
<Toast />
<TutorialContainer />
<MainContent>{children}</MainContent>
</Providers>
</body>
Expand Down
45 changes: 45 additions & 0 deletions src/app/search/[id]/_components/tutorial/constant/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { TutorialStep } from "../types";

const TUTORIAL_STEPS: TutorialStep[] = [
{
title: "차트 보기",
content: [
{
subtitle: "기간 설정",
description: "일/주/월 버튼으로 원하는 기간의 차트를 확인하세요.",
},
{
subtitle: "이동평균선(MA)",
description: "MA 버튼으로 주가의 평균 추세선을 표시할 수 있어요.",
},
],
},
{
title: "거래하기",
content: [
{
subtitle: "매수/매도",
description: "원하는 거래 유형을 선택하고 수량과 가격을 입력하세요.",
},
{
subtitle: "실시간 호가",
description: "현재 매수/매도 호가를 실시간으로 확인할 수 있어요.",
},
],
},
{
title: "주문 관리",
content: [
{
subtitle: "체결 내역",
description: "체결내역 탭에서 완료된 거래를 확인하세요.",
},
{
subtitle: "미체결 주문",
description: "정정/취소 탭에서 아직 체결되지 않은 주문을 관리하세요.",
},
],
},
];

export default TUTORIAL_STEPS;
23 changes: 23 additions & 0 deletions src/app/search/[id]/_components/tutorial/tutorial-container.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"use client";

import { useEffect, useState } from "react";

import ChartTutorialModal from "./tutorial-modal";

export default function ChartTutorialContainer() {
const [isOpen, setIsOpen] = useState(false);

useEffect(() => {
const hasCompletedTutorial = localStorage.getItem(
"chart-tutorial-completed",
);
if (!hasCompletedTutorial) {
setIsOpen(true);
localStorage.setItem("chart-tutorial-completed", "true");
}
}, []);
Comment on lines +10 to +18
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

localStorage 접근 및 상태 관리 개선 필요

다음과 같은 개선사항을 고려해주세요:

  1. localStorage 접근 시 예외 처리가 필요합니다
  2. 튜토리얼을 실제로 완료했을 때 localStorage에 저장하는 것이 더 적절할 수 있습니다

다음과 같이 개선해보세요:

 useEffect(() => {
-  const hasCompletedTutorial = localStorage.getItem(
-    "chart-tutorial-completed",
-  );
-  if (!hasCompletedTutorial) {
-    setIsOpen(true);
-    localStorage.setItem("chart-tutorial-completed", "true");
-  }
+  try {
+    const hasCompletedTutorial = localStorage.getItem(
+      "chart-tutorial-completed",
+    );
+    if (!hasCompletedTutorial) {
+      setIsOpen(true);
+    }
+  } catch (error) {
+    console.error('로컬 스토리지 접근 중 오류 발생:', error);
+  }
 }, []);

Committable suggestion skipped: line range outside the PR's diff.


return (
<ChartTutorialModal isOpen={isOpen} onClose={() => setIsOpen(false)} />
);
}
88 changes: 88 additions & 0 deletions src/app/search/[id]/_components/tutorial/tutorial-modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
"use client";

import { ChevronLeft, ChevronRight, X } from "lucide-react";
import { useCallback, useState } from "react";

import BaseModal from "@/components/common/modal";
import TutorialContent from "@/components/common/tutorial/_components/tutorial-contents";

import TUTORIAL_STEPS from "./constant";

interface TutorialModalProps {
isOpen: boolean;
onClose: () => void;
}

export default function TutorialModal({ isOpen, onClose }: TutorialModalProps) {
const [currentStep, setCurrentStep] = useState(0);

const handleNext = useCallback(() => {
setCurrentStep((prev) => Math.min(prev + 1, TUTORIAL_STEPS.length - 1));
}, []);

const handlePrev = useCallback(() => {
setCurrentStep((prev) => Math.max(prev - 1, 0));
}, []);

const handleComplete = useCallback(() => {
if (typeof window !== "undefined") {
localStorage.setItem("stock-tutorial-completed", "true");
}
onClose();
}, [onClose]);
Comment on lines +27 to +32
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

localStorage 접근 시 예외 처리 필요

localStorage 접근 시 발생할 수 있는 예외 상황(private 모드 등)에 대한 처리가 필요합니다.

  const handleComplete = useCallback(() => {
    if (typeof window !== "undefined") {
+     try {
        localStorage.setItem("stock-tutorial-completed", "true");
+     } catch (error) {
+       console.error("Failed to save tutorial status:", error);
+     }
    }
    onClose();
  }, [onClose]);
📝 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
const handleComplete = useCallback(() => {
if (typeof window !== "undefined") {
localStorage.setItem("stock-tutorial-completed", "true");
}
onClose();
}, [onClose]);
const handleComplete = useCallback(() => {
if (typeof window !== "undefined") {
try {
localStorage.setItem("stock-tutorial-completed", "true");
} catch (error) {
console.error("Failed to save tutorial status:", error);
}
}
onClose();
}, [onClose]);


return (
<BaseModal isOpen={isOpen} onClose={onClose}>
<div className="shadow-xl rounded-lg bg-white px-26 py-20">
<div className="mb-15 flex items-center justify-between">
<h2 className="text-24-600 text-gray-900">주식 거래 시작하기</h2>
<button
type="button"
onClick={onClose}
className="rounded-full p-1 hover:bg-gray-100"
>
<X className="size-25 text-gray-500" />
</button>
</div>
Comment on lines +39 to +46
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

접근성 개선 필요

버튼 요소들에 대한 접근성 속성이 누락되어 있습니다. 스크린 리더 사용자를 위한 aria 속성 추가가 필요합니다.

  <button
    type="button"
    onClick={onClose}
+   aria-label="튜토리얼 닫기"
    className="rounded-full p-1 hover:bg-gray-100"
  >
    <X className="size-25 text-gray-500" />
  </button>

  <button
    type="button"
    onClick={handlePrev}
+   aria-label="이전 단계로 이동"
    className="flex items-center gap-4 rounded-md border border-gray-300 px-8 py-4 text-16-600 text-gray-700 hover:bg-gray-50"
  >

Also applies to: 56-64, 66-74, 75-82


<TutorialContent step={TUTORIAL_STEPS[currentStep]} />

<div className="flex items-center justify-between">
<div className="text-16-600 text-gray-500">
{currentStep + 1} / {TUTORIAL_STEPS.length}
</div>
<div className="flex gap-10">
{currentStep > 0 && (
<button
type="button"
onClick={handlePrev}
className="flex items-center gap-4 rounded-md border border-gray-300 px-8 py-4 text-16-600 text-gray-700 hover:bg-gray-50"
>
<ChevronLeft className="size-16" />
이전
</button>
)}
{currentStep < TUTORIAL_STEPS.length - 1 ? (
<button
type="button"
onClick={handleNext}
className="flex items-center gap-4 rounded-md bg-green-500 px-8 py-4 text-16-600 text-white hover:bg-green-600"
>
다음
<ChevronRight className="size-16" />
</button>
) : (
<button
type="button"
onClick={handleComplete}
className="rounded-md bg-green-500 px-8 py-4 text-16-600 text-white hover:bg-green-600"
>
시작하기
</button>
)}
</div>
</div>
</div>
</BaseModal>
);
}
9 changes: 9 additions & 0 deletions src/app/search/[id]/_components/tutorial/types/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export interface TutorialContentItem {
subtitle: string;
description: string;
}

export interface TutorialStep {
title: string;
content: TutorialContentItem[];
}
Comment on lines +1 to +9
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

중복된 타입 정의 제거 필요

동일한 인터페이스가 src/components/common/tutorial/types/index.ts에도 정의되어 있습니다. 코드 중복을 피하고 유지보수성을 높이기 위해 다음과 같은 개선이 필요합니다:

  1. common 디렉토리의 타입 정의를 재사용
  2. 필요한 타입만 import하여 사용

다음과 같이 수정하는 것을 제안합니다:

-export interface TutorialContentItem {
-  subtitle: string;
-  description: string;
-}
-
-export interface TutorialStep {
-  title: string;
-  content: TutorialContentItem[];
-}
+import type { TutorialContentItem, TutorialStep } from '@/components/common/tutorial/types';
+
+export type { TutorialContentItem, TutorialStep };
📝 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
export interface TutorialContentItem {
subtitle: string;
description: string;
}
export interface TutorialStep {
title: string;
content: TutorialContentItem[];
}
import type { TutorialContentItem, TutorialStep } from '@/components/common/tutorial/types';
export type { TutorialContentItem, TutorialStep };

2 changes: 2 additions & 0 deletions src/app/search/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Link from "next/link";
import CandlestickChartContainer from "./_components/candle-chart-container";
import StockHeader from "./_components/stock-header";
import TransactionForm from "./_components/transaction-form";
import TutorialContainer from "./_components/tutorial/tutorial-container";
import { ChartResponse, StockInfo, VolumeResponse } from "./types";

async function getInitialData(id: string) {
Expand Down Expand Up @@ -59,6 +60,7 @@ export default async function StockPage({
const stockName = decodeURIComponent(params.id);
return (
<div className="p-30">
<TutorialContainer />
<StockHeader
stockName={params.id}
initialStockInfo={initialData.stockData}
Expand Down
20 changes: 20 additions & 0 deletions src/components/common/tutorial/_components/tutorial-container.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"use client";

import { useEffect, useState } from "react";

import TutorialModal from "./tutorial-modal";

export default function TutorialContainer() {
const [isOpen, setIsOpen] = useState(false);

useEffect(() => {
const hasCompletedTutorial = localStorage.getItem("nav-tutorial-completed");
if (!hasCompletedTutorial) {
setIsOpen(true);
// 튜토리얼을 본 것으로 표시
localStorage.setItem("nav-tutorial-completed", "true");
}
}, []);
Comment on lines +10 to +17
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

localStorage 접근 및 useEffect 개선 필요

localStorage 접근 시 발생할 수 있는 예외 처리와 useEffect의 안전한 구현이 필요합니다.

다음과 같이 수정하는 것을 제안합니다:

+const TUTORIAL_COMPLETED_KEY = 'nav-tutorial-completed';
+
 export default function TutorialContainer() {
   const [isOpen, setIsOpen] = useState(false);
 
   useEffect(() => {
-    const hasCompletedTutorial = localStorage.getItem("nav-tutorial-completed");
-    if (!hasCompletedTutorial) {
-      setIsOpen(true);
-      // 튜토리얼을 본 것으로 표시
-      localStorage.setItem("nav-tutorial-completed", "true");
+    try {
+      const hasCompletedTutorial = localStorage.getItem(TUTORIAL_COMPLETED_KEY);
+      if (!hasCompletedTutorial) {
+        setIsOpen(true);
+        localStorage.setItem(TUTORIAL_COMPLETED_KEY, 'true');
+      }
+    } catch (error) {
+      console.error('튜토리얼 상태 저장 중 오류 발생:', error);
     }
+    
+    return () => {
+      // cleanup 로직이 필요한 경우 여기에 추가
+    };
   }, []);
📝 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
useEffect(() => {
const hasCompletedTutorial = localStorage.getItem("nav-tutorial-completed");
if (!hasCompletedTutorial) {
setIsOpen(true);
// 튜토리얼을 본 것으로 표시
localStorage.setItem("nav-tutorial-completed", "true");
}
}, []);
const TUTORIAL_COMPLETED_KEY = 'nav-tutorial-completed';
useEffect(() => {
try {
const hasCompletedTutorial = localStorage.getItem(TUTORIAL_COMPLETED_KEY);
if (!hasCompletedTutorial) {
setIsOpen(true);
localStorage.setItem(TUTORIAL_COMPLETED_KEY, 'true');
}
} catch (error) {
console.error('튜토리얼 상태 저장 중 오류 발생:', error);
}
return () => {
// cleanup 로직이 필요한 경우 여기에 추가
};
}, []);


return <TutorialModal isOpen={isOpen} onClose={() => setIsOpen(false)} />;
}
26 changes: 26 additions & 0 deletions src/components/common/tutorial/_components/tutorial-contents.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/* eslint-disable */

import { TutorialStep } from "../types";

interface TutorialContentProps {
step: TutorialStep;
}

export default function TutorialContent({ step }: TutorialContentProps) {
return (
<div className="mb-20">
<h3 className="text-20-500 mb-10 font-semibold text-gray-800">
{step.title}
</h3>

<div className="space-y-20">
{step.content.map((item, idx) => (
<div key={`${step.title}-content-${idx}`}>
<h4 className="text-16-600 text-gray-700 mb-10">{item.subtitle}</h4>
<p className="text-14-500 text-gray-600">{item.description}</p>
</div>
))}
</div>
</div>
Comment on lines +11 to +24
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

접근성 및 시맨틱 마크업 개선 필요

현재 구조에 다음과 같은 개선이 필요합니다:

  1. 시맨틱한 HTML 구조 사용
  2. 접근성 속성 추가
  3. 더 안정적인 키 생성 방식 적용

다음과 같이 개선해보세요:

-    <div className="mb-20">
+    <section className="mb-20" aria-labelledby="tutorial-title">
-      <h3 className="text-20-500 mb-10 font-semibold text-gray-800">
+      <h3 id="tutorial-title" className="text-20-500 mb-10 font-semibold text-gray-800">
         {step.title}
       </h3>

-      <div className="space-y-20">
+      <ul className="space-y-20 list-none" role="list">
         {step.content.map((item, idx) => (
-          <div key={`${step.title}-content-${idx}`}>
+          <li key={`${step.title}-${item.subtitle}-${idx}`}>
             <h4 className="text-16-600 text-gray-700 mb-10">{item.subtitle}</h4>
             <p className="text-14-500 text-gray-600">{item.description}</p>
-          </div>
+          </li>
         ))}
-      </div>
-    </div>
+      </ul>
+    </section>
📝 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
<div className="mb-20">
<h3 className="text-20-500 mb-10 font-semibold text-gray-800">
{step.title}
</h3>
<div className="space-y-20">
{step.content.map((item, idx) => (
<div key={`${step.title}-content-${idx}`}>
<h4 className="text-16-600 text-gray-700 mb-10">{item.subtitle}</h4>
<p className="text-14-500 text-gray-600">{item.description}</p>
</div>
))}
</div>
</div>
<section className="mb-20" aria-labelledby="tutorial-title">
<h3 id="tutorial-title" className="text-20-500 mb-10 font-semibold text-gray-800">
{step.title}
</h3>
<ul className="space-y-20 list-none" role="list">
{step.content.map((item, idx) => (
<li key={`${step.title}-${item.subtitle}-${idx}`}>
<h4 className="text-16-600 text-gray-700 mb-10">{item.subtitle}</h4>
<p className="text-14-500 text-gray-600">{item.description}</p>
</li>
))}
</ul>
</section>

);
}
110 changes: 110 additions & 0 deletions src/components/common/tutorial/_components/tutorial-modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
"use client";

import { ChevronLeft, ChevronRight, X } from "lucide-react";
import { useRouter } from "next/navigation";
import { useCallback, useState } from "react";

import BaseModal from "@/components/common/modal";

import TUTORIAL_STEPS from "../constant";
import TutorialContent from "./tutorial-contents";

interface TutorialModalProps {
isOpen: boolean;
onClose: () => void;
}

export default function TutorialModal({ isOpen, onClose }: TutorialModalProps) {
const [currentStep, setCurrentStep] = useState(0);
const router = useRouter();

// 스텝에 따른 경로 반환
const getPathForStep = (step: number) => {
switch (step) {
case 0:
return "/";
case 1:
return "/search";
case 2:
return "/my-account";
case 3:
return "/portfolio";
default:
return "/";
}
};
Comment on lines +21 to +35
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

라우팅 로직 개선 필요

현재 구현된 getPathForStep 함수는 하드코딩된 경로를 사용하고 있어 유지보수가 어려울 수 있습니다. 상수로 분리하거나 설정 파일로 관리하는 것이 좋습니다.

다음과 같이 개선해보세요:

+ const STEP_PATHS = {
+   0: "/",
+   1: "/search",
+   2: "/my-account",
+   3: "/portfolio"
+ } as const;

  const getPathForStep = (step: number) => {
-   switch (step) {
-     case 0:
-       return "/";
-     case 1:
-       return "/search";
-     case 2:
-       return "/my-account";
-     case 3:
-       return "/portfolio";
-     default:
-       return "/";
-   }
+   return STEP_PATHS[step as keyof typeof STEP_PATHS] || "/";
  };
📝 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
// 스텝에 따른 경로 반환
const getPathForStep = (step: number) => {
switch (step) {
case 0:
return "/";
case 1:
return "/search";
case 2:
return "/my-account";
case 3:
return "/portfolio";
default:
return "/";
}
};
const STEP_PATHS = {
0: "/",
1: "/search",
2: "/my-account",
3: "/portfolio"
} as const;
// 스텝에 따른 경로 반환
const getPathForStep = (step: number) => {
return STEP_PATHS[step as keyof typeof STEP_PATHS] || "/";
};


const handleNext = useCallback(() => {
setCurrentStep((prev) => Math.min(prev + 1, TUTORIAL_STEPS.length - 1));
// 페이지 이동
router.push(getPathForStep(currentStep + 1));
}, [currentStep, router]);

const handlePrev = useCallback(() => {
setCurrentStep((prev) => Math.max(prev - 1, 0));
// 페이지 이동
router.push(getPathForStep(currentStep - 1));
}, [currentStep, router]);

const handleComplete = useCallback(() => {
if (typeof window !== "undefined") {
localStorage.setItem("nav-tutorial-completed", "true");
}
onClose();
}, [onClose]);
Comment on lines +49 to +54
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

localStorage 접근 에러 처리 개선 필요

localStorage 접근 시 발생할 수 있는 예외 상황(예: 사용자가 쿠키를 차단한 경우)에 대한 처리가 필요합니다.

다음과 같이 개선해보세요:

  const handleComplete = useCallback(() => {
    if (typeof window !== "undefined") {
+     try {
        localStorage.setItem("nav-tutorial-completed", "true");
+     } catch (error) {
+       console.error("Failed to save tutorial state:", error);
+     }
    }
    onClose();
  }, [onClose]);
📝 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
const handleComplete = useCallback(() => {
if (typeof window !== "undefined") {
localStorage.setItem("nav-tutorial-completed", "true");
}
onClose();
}, [onClose]);
const handleComplete = useCallback(() => {
if (typeof window !== "undefined") {
try {
localStorage.setItem("nav-tutorial-completed", "true");
} catch (error) {
console.error("Failed to save tutorial state:", error);
}
}
onClose();
}, [onClose]);


return (
<BaseModal isOpen={isOpen} onClose={onClose}>
<div className="shadow-xl rounded-lg bg-white px-26 py-20">
<div className="mb-15 flex items-center justify-between">
<h2 className="text-24-600 text-gray-900">GrowFoilo 둘러보기</h2>
<button
type="button"
onClick={onClose}
className="rounded-full p-3 hover:bg-gray-100"
>
<X className="size-25 text-gray-500" />
</button>
</div>

<TutorialContent step={TUTORIAL_STEPS[currentStep]} />

<div className="flex items-center justify-between">
<div className="text-16-600 text-gray-500">
{currentStep + 1} / {TUTORIAL_STEPS.length}
</div>
<div className="flex gap-10">
{currentStep > 0 && (
<button
type="button"
onClick={handlePrev}
className="flex items-center gap-4 rounded-md border border-gray-300 px-8 py-4 text-16-600 text-gray-700 hover:bg-gray-50"
>
<ChevronLeft className="size-16" />
이전
</button>
)}
{currentStep < TUTORIAL_STEPS.length - 1 ? (
<button
type="button"
onClick={handleNext}
className="flex items-center gap-4 rounded-md bg-green-500 px-8 py-4 text-16-600 text-white hover:bg-green-600"
>
다음
<ChevronRight className="size-16" />
</button>
) : (
<button
type="button"
onClick={handleComplete}
className="rounded-md bg-green-500 px-8 py-4 text-16-600 text-white hover:bg-green-600"
>
시작하기
</button>
)}
</div>
</div>
</div>
</BaseModal>
Comment on lines +56 to +108
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

접근성 개선 필요

모달 컴포넌트의 접근성이 부족합니다. 키보드 네비게이션과 스크린 리더 지원을 추가해야 합니다.

다음 개선사항을 적용해주세요:

  1. ARIA 레이블 추가:
- <div className="shadow-xl rounded-lg bg-white px-26 py-20">
+ <div 
+   className="shadow-xl rounded-lg bg-white px-26 py-20"
+   role="dialog"
+   aria-labelledby="tutorial-title"
+   aria-describedby="tutorial-desc"
+ >
  1. 키보드 네비게이션:
  <button
    type="button"
    onClick={handleNext}
+   onKeyDown={(e) => e.key === 'Enter' && handleNext()}
    className="flex items-center gap-4 rounded-md bg-green-500 px-8 py-4 text-16-600 text-white hover:bg-green-600"
  >

Committable suggestion skipped: line range outside the PR's diff.

);
}
Loading
Loading