Skip to Content
ExamplesDashboard Example (iCignal)

Dashboard Example (iCignal)

분석 대시보드 구현 예제


개요

iCignal 전용 AnalyticsCard 컴포넌트를 활용한 실시간 분석 대시보드 예제입니다.

주요 특징

  • ✅ Real-time Analytics Cards
  • ✅ Trend Indicators
  • ✅ Chart Integration
  • ✅ Responsive Grid Layout
  • ✅ Data Refresh

전체 코드

"use client"; import { useState, useEffect } from "react"; import { AnalyticsCard } from "@vortex/ui-icignal"; import { Container } from "@/components/ui/container"; import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Button } from "@vortex/ui-icignal"; export default function Dashboard() { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { fetchDashboardData(); }, []); const fetchDashboardData = async () => { setLoading(true); // API 호출 시뮬레이션 await new Promise((resolve) => setTimeout(resolve, 1000)); setData({ users: { value: "12,345", trend: "+12%", trendUp: true }, revenue: { value: "$45,678", trend: "+8%", trendUp: true }, orders: { value: "1,234", trend: "-3%", trendUp: false }, conversion: { value: "3.2%", trend: "+0.5%", trendUp: true }, }); setLoading(false); }; if (loading) { return ( <Container size="xl" className="py-8"> <div className="animate-pulse space-y-6"> <div className="h-8 bg-muted rounded w-64"></div> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6"> {[...Array(4)].map((_, i) => ( <div key={i} className="h-32 bg-muted rounded"></div> ))} </div> </div> </Container> ); } return ( <Container size="xl" className="py-8 space-y-8"> {/* Header */} <div className="flex items-center justify-between"> <div> <h1 className="text-3xl font-bold">Analytics Dashboard</h1> <p className="text-muted-foreground"> 실시간 비즈니스 지표를 확인하세요 </p> </div> <Button onClick={fetchDashboardData}>Refresh</Button> </div> {/* Metrics Grid */} <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6"> <AnalyticsCard title="Total Users" value={data.users.value} trend={data.users.trend} trendUp={data.users.trendUp} description="Active users this month" /> <AnalyticsCard title="Revenue" value={data.revenue.value} trend={data.revenue.trend} trendUp={data.revenue.trendUp} description="Total revenue this month" /> <AnalyticsCard title="Orders" value={data.orders.value} trend={data.orders.trend} trendUp={data.orders.trendUp} description="Total orders this month" /> <AnalyticsCard title="Conversion Rate" value={data.conversion.value} trend={data.conversion.trend} trendUp={data.conversion.trendUp} description="Average conversion rate" /> </div> {/* Tabs for Different Views */} <Tabs defaultValue="overview" className="space-y-4"> <TabsList> <TabsTrigger value="overview">Overview</TabsTrigger> <TabsTrigger value="analytics">Analytics</TabsTrigger> <TabsTrigger value="reports">Reports</TabsTrigger> </TabsList> <TabsContent value="overview" className="space-y-4"> <div className="grid grid-cols-1 lg:grid-cols-2 gap-6"> <Card> <CardHeader> <CardTitle>Recent Activity</CardTitle> </CardHeader> <CardContent> <div className="space-y-4"> <div className="flex items-center justify-between"> <div> <p className="font-medium">New user registration</p> <p className="text-sm text-muted-foreground"> 2 minutes ago </p> </div> <span className="text-sm text-green-600">+1</span> </div> <div className="flex items-center justify-between"> <div> <p className="font-medium">Order completed</p> <p className="text-sm text-muted-foreground"> 5 minutes ago </p> </div> <span className="text-sm text-green-600">+$234</span> </div> <div className="flex items-center justify-between"> <div> <p className="font-medium">Payment received</p> <p className="text-sm text-muted-foreground"> 12 minutes ago </p> </div> <span className="text-sm text-green-600">+$567</span> </div> </div> </CardContent> </Card> <Card> <CardHeader> <CardTitle>Top Products</CardTitle> </CardHeader> <CardContent> <div className="space-y-4"> <div className="flex items-center justify-between"> <div> <p className="font-medium">Product A</p> <p className="text-sm text-muted-foreground">234 sales</p> </div> <span className="text-sm font-medium">$12,345</span> </div> <div className="flex items-center justify-between"> <div> <p className="font-medium">Product B</p> <p className="text-sm text-muted-foreground">189 sales</p> </div> <span className="text-sm font-medium">$9,876</span> </div> <div className="flex items-center justify-between"> <div> <p className="font-medium">Product C</p> <p className="text-sm text-muted-foreground">145 sales</p> </div> <span className="text-sm font-medium">$7,654</span> </div> </div> </CardContent> </Card> </div> </TabsContent> <TabsContent value="analytics"> <Card> <CardHeader> <CardTitle>Analytics Overview</CardTitle> </CardHeader> <CardContent> <p className="text-muted-foreground"> 차트 및 상세 분석 데이터가 여기에 표시됩니다. </p> </CardContent> </Card> </TabsContent> <TabsContent value="reports"> <Card> <CardHeader> <CardTitle>Reports</CardTitle> </CardHeader> <CardContent> <p className="text-muted-foreground"> 생성된 리포트 목록이 여기에 표시됩니다. </p> </CardContent> </Card> </TabsContent> </Tabs> </Container> ); }

주요 패턴

실시간 데이터 로딩

const [data, setData] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { fetchDashboardData(); // 30초마다 자동 새로고침 const interval = setInterval(fetchDashboardData, 30000); return () => clearInterval(interval); }, []);

AnalyticsCard 사용

<AnalyticsCard title="Total Users" value="12,345" trend="+12%" trendUp={true} description="Active users this month" />

Props:

  • title: 지표 이름
  • value: 현재 값
  • trend: 증감 비율
  • trendUp: 상승/하락 표시
  • description: 부가 설명

반응형 그리드

<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6"> {/* 모바일: 1열, 태블릿: 2열, 데스크톱: 4열 */} </div>

API 통합

데이터 페칭

const fetchDashboardData = async () => { try { const response = await fetch("/api/analytics/dashboard"); const data = await response.json(); setData(data); } catch (error) { console.error("Failed to fetch dashboard data:", error); } finally { setLoading(false); } };

TanStack Query 사용

import { useQuery } from "@tanstack/react-query"; function Dashboard() { const { data, isLoading, refetch } = useQuery({ queryKey: ["dashboard"], queryFn: fetchDashboardData, refetchInterval: 30000, // 30초마다 자동 새로고침 }); return <Button onClick={() => refetch()}>Refresh</Button>; }

로딩 상태

if (loading) { return ( <div className="animate-pulse space-y-6"> <div className="h-8 bg-muted rounded w-64"></div> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6"> {[...Array(4)].map((_, i) => ( <div key={i} className="h-32 bg-muted rounded"></div> ))} </div> </div> ); }

차트 통합

Recharts 예제

import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, } from "recharts"; <Card> <CardHeader> <CardTitle>Revenue Trend</CardTitle> </CardHeader> <CardContent> <LineChart width={600} height={300} data={chartData}> <CartesianGrid strokeDasharray="3 3" /> <XAxis dataKey="name" /> <YAxis /> <Tooltip /> <Line type="monotone" dataKey="revenue" stroke="#8884d8" /> </LineChart> </CardContent> </Card>;

다음 단계

Last updated on