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
4 changes: 3 additions & 1 deletion src/api/news/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { News } from "@/app/main/types/index";

async function getNews(): Promise<News[]> {
const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/home/news`);
const response: Response = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/home/news`,
);
if (!response.ok) {
throw new Error("Failed to fetch news");
}
Expand Down
4 changes: 2 additions & 2 deletions src/app/main/_components/news-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ function NewsCard({ title, link }: NewsCardProps) {
<button
type="button"
onClick={handleClick}
className="h-281 w-308 overflow-hidden rounded-lg bg-white text-left transition-shadow hover:shadow-md"
className="hover:shadow-md h-281 w-308 overflow-hidden rounded-lg bg-white text-left transition-shadow"
>
<div className="relative h-182 overflow-hidden pt-0">
<Image
Expand All @@ -28,7 +28,7 @@ function NewsCard({ title, link }: NewsCardProps) {
<div className="p-6">
<div className="group relative">
<h3 className="mt-5 truncate text-16-600 text-gray-900">{title}</h3>
<div className="absolute left-0 z-20 hidden max-w-308 rounded-md bg-white p-2 text-14-400 shadow-lg group-hover:block">
<div className="shadow-lg absolute left-0 z-20 hidden max-w-308 rounded-md bg-white p-2 text-14-400 group-hover:block">
{title}
</div>
</div>
Expand Down
31 changes: 24 additions & 7 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import RankingStock from "@/app/main/_components/ranking-stock";
import SearchStock from "@/app/main/_components/search-stock";
import StockIndexCarousel from "@/app/main/_components/stock-carousel";
import MyStockInfo from "@/app/main/_components/stock-info";
import ErrorBoundary from "@/components/common/error-boundary";

export default async function Home() {
const queryClient = new QueryClient({
Expand Down Expand Up @@ -44,26 +45,42 @@ export default async function Home() {
<div className="flex xxl:px-230">
{/* 메인 컨텐츠 */}
<div className="flex flex-1 flex-col p-10 pt-30 md:px-32 lg:max-w-[calc(100%-320px)]">
<SearchStock />
<StockIndexCarousel initialData={initialStockData} />
<ErrorBoundary errorMessage="검색 기능을 일시적으로 사용할 수 없습니다">
<SearchStock />
</ErrorBoundary>

<ErrorBoundary errorMessage="주가 정보를 불러올 수 없습니다">
<StockIndexCarousel initialData={initialStockData} />
</ErrorBoundary>

<div className="flex flex-col gap-20">
<h2 className="mt-80 text-24-700">실시간 랭킹</h2>
<div className="flex w-full gap-30">
<div className="mr-50 w-full">
<RankingStock data={traddata} />
<ErrorBoundary errorMessage="거래량 순위를 불러올 수 없습니다">
<RankingStock data={traddata} />
</ErrorBoundary>
</div>
<div className="w-full">
<FluctuationTable data={flucdata} />
<ErrorBoundary errorMessage="변동폭 순위를 불러올 수 없습니다">
<FluctuationTable data={flucdata} />
</ErrorBoundary>
</div>
</div>
<NewsCarousel initialData={initialNews} />
<ErrorBoundary errorMessage="뉴스를 불러올 수 없습니다">
<NewsCarousel initialData={initialNews} />
</ErrorBoundary>
</div>
</div>
{/* 우측 사이드바 */}
<div className="w-330 shrink-0">
<div className="sticky top-24 flex flex-col gap-16">
<AssetInfo />
<MyStockInfo />
<ErrorBoundary errorMessage="자산 정보를 불러올 수 없습니다">
<AssetInfo />
</ErrorBoundary>
<ErrorBoundary errorMessage="관심 종목을 불러올 수 없습니다">
<MyStockInfo />
</ErrorBoundary>
</div>
</div>
</div>
Expand Down
4 changes: 2 additions & 2 deletions src/components/common/dropdown/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ function Wrapper({
{isOpen && (
<motion.div
className={cn(
"rounded-2 w-full shadow-custom absolute z-50 border-[#B6B6B6] border border-solid bg-white p-8",
"rounded-2 w-full shadow-custom absolute z-50 border-[#B6B6B6] border border-solid bg-white py-10 px-12",
className,
)}
initial={{ opacity: 0, y: -10 }}
Expand Down Expand Up @@ -158,7 +158,7 @@ function Item({ children, value, className }: ItemProps): JSX.Element {
<button
type="button"
className={cn(
"transition-linear text-black/80 rounded-2 relative w-full px-12 py-6 text-left hover:bg-gray-100 focus:bg-green-700/5 focus:!text-green-900",
"transition-linear text-black/80 rounded-2 relative w-full py-10 text-left hover:bg-gray-100 focus:bg-green-700/5 focus:!text-green-900",
{
"bg-green-500/10 !text-green-900": isSelected,
},
Expand Down
68 changes: 68 additions & 0 deletions src/components/common/error-boundary/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
"use client";

import { RefreshCw } from "lucide-react";
import React, { Component, ErrorInfo, ReactNode } from "react";

interface ErrorBoundaryProps {
children: ReactNode;
errorMessage?: string;
description?: string;
className?: string;
}

interface ErrorBoundaryState {
hasError: boolean;
}

class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
constructor(props: ErrorBoundaryProps) {
super(props);
this.state = { hasError: false };
}

static getDerivedStateFromError(): ErrorBoundaryState {
return { hasError: true };
}

componentDidCatch(error: Error, errorInfo: ErrorInfo): void {
console.error("Error Boundary caught an error:", error, errorInfo); //eslint-disable-line
}
Comment on lines +27 to +29
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

에러 로깅 개선이 필요합니다

현재 콘솔 로그만 사용하고 있는데, 프로덕션 환경에서는 에러 추적 서비스(예: Sentry)를 활용하는 것이 좋습니다.

  componentDidCatch(error: Error, errorInfo: ErrorInfo): void {
-   console.error("Error Boundary caught an error:", error, errorInfo); //eslint-disable-line
+   // TODO: Sentry 또는 다른 에러 추적 서비스 연동
+   if (process.env.NODE_ENV === 'production') {
+     // captureException(error, { extra: errorInfo });
+   } else {
+     console.error("Error Boundary caught an error:", error, errorInfo);
+   }
  }

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


handleRefresh = () => {
this.setState({ hasError: false });
};

render(): ReactNode {
const { hasError } = this.state;
if (hasError) {
const {
errorMessage = "문제가 발생했습니다",
description = "새로고침을 통해 다시 시도해 주세요.",
className = "",
} = this.props;

return (
<div
className={`flex flex-col items-center justify-center p-16 text-center ${className}`}
>
<div className="mb-8 text-red-500">⚠️</div>
<h3 className="mb-4 text-18-700">{errorMessage}</h3>
<p className="mb-6 text-14-400 text-gray-600">{description}</p>
<button
type="button"
onClick={this.handleRefresh}
className="inline-flex items-center gap-2 rounded-md bg-blue-500 px-4 py-2 text-14-600 text-white hover:bg-blue-600 active:bg-blue-700"
>
<RefreshCw size={16} />
<span>새로고침</span>
</button>
</div>
);
}

const { children } = this.props;
return children;
}
}

export default ErrorBoundary;
Loading