Analytics Report Example (iCignal)
상세 분석 리포트 구현 예제
개요
iCignal의 AnalyticsCard와 차트를 결합한 종합 리포트 페이지 예제입니다.
주요 특징
- ✅ 기간별 리포트 생성
- ✅ 다양한 차트 타입
- ✅ PDF 내보내기
- ✅ 필터링 및 정렬
- ✅ 데이터 비교
전체 코드
"use client";
import { useState } from "react";
import { AnalyticsCard } from "@vortex/ui-icignal";
import { Container } from "@/components/ui/container";
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
import { Button } from "@vortex/ui-icignal";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { DatePickerWithRange } from "@/components/ui/date-range-picker";
export default function AnalyticsReport() {
const [period, setPeriod] = useState("30d");
const [dateRange, setDateRange] = useState(null);
const exportToPDF = () => {
// PDF 내보내기 로직
console.log("Exporting to PDF...");
};
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 Report</h1>
<p className="text-muted-foreground">기간별 상세 분석 리포트</p>
</div>
<div className="flex gap-2">
<Button variant="outline" onClick={exportToPDF}>
Export PDF
</Button>
<Button>Share</Button>
</div>
</div>
{/* Filters */}
<Card>
<CardContent className="py-4">
<div className="flex gap-4 flex-wrap">
<Select value={period} onValueChange={setPeriod}>
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="기간 선택" />
</SelectTrigger>
<SelectContent>
<SelectItem value="7d">최근 7일</SelectItem>
<SelectItem value="30d">최근 30일</SelectItem>
<SelectItem value="90d">최근 90일</SelectItem>
<SelectItem value="custom">사용자 지정</SelectItem>
</SelectContent>
</Select>
{period === "custom" && (
<DatePickerWithRange value={dateRange} onChange={setDateRange} />
)}
<Button variant="outline">Apply Filters</Button>
</div>
</CardContent>
</Card>
{/* Summary Cards */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
<AnalyticsCard
title="Page Views"
value="45,678"
trend="+15%"
trendUp={true}
description="vs. previous period"
/>
<AnalyticsCard
title="Unique Visitors"
value="12,345"
trend="+8%"
trendUp={true}
description="vs. previous period"
/>
<AnalyticsCard
title="Avg. Session"
value="4m 32s"
trend="-2%"
trendUp={false}
description="vs. previous period"
/>
<AnalyticsCard
title="Bounce Rate"
value="42.3%"
trend="-5%"
trendUp={true}
description="vs. previous period"
/>
</div>
{/* Charts */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
<Card>
<CardHeader>
<CardTitle>Traffic Over Time</CardTitle>
</CardHeader>
<CardContent>
<div className="h-[300px] flex items-center justify-center bg-muted/50 rounded">
<p className="text-muted-foreground">
Line Chart: 시간별 트래픽 추이
</p>
</div>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Traffic Sources</CardTitle>
</CardHeader>
<CardContent>
<div className="h-[300px] flex items-center justify-center bg-muted/50 rounded">
<p className="text-muted-foreground">
Pie Chart: 트래픽 소스 분포
</p>
</div>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Top Pages</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-4">
<div className="flex items-center justify-between">
<div className="flex-1">
<p className="font-medium">/products</p>
<div className="w-full bg-muted rounded-full h-2 mt-1">
<div
className="bg-primary h-2 rounded-full"
style={{ width: "85%" }}
></div>
</div>
</div>
<span className="ml-4 text-sm font-medium">12,345</span>
</div>
<div className="flex items-center justify-between">
<div className="flex-1">
<p className="font-medium">/about</p>
<div className="w-full bg-muted rounded-full h-2 mt-1">
<div
className="bg-primary h-2 rounded-full"
style={{ width: "65%" }}
></div>
</div>
</div>
<span className="ml-4 text-sm font-medium">9,876</span>
</div>
<div className="flex items-center justify-between">
<div className="flex-1">
<p className="font-medium">/contact</p>
<div className="w-full bg-muted rounded-full h-2 mt-1">
<div
className="bg-primary h-2 rounded-full"
style={{ width: "45%" }}
></div>
</div>
</div>
<span className="ml-4 text-sm font-medium">6,543</span>
</div>
</div>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>User Demographics</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-4">
<div>
<div className="flex items-center justify-between mb-2">
<span className="text-sm">Desktop</span>
<span className="text-sm font-medium">58%</span>
</div>
<div className="w-full bg-muted rounded-full h-2">
<div
className="bg-blue-500 h-2 rounded-full"
style={{ width: "58%" }}
></div>
</div>
</div>
<div>
<div className="flex items-center justify-between mb-2">
<span className="text-sm">Mobile</span>
<span className="text-sm font-medium">35%</span>
</div>
<div className="w-full bg-muted rounded-full h-2">
<div
className="bg-green-500 h-2 rounded-full"
style={{ width: "35%" }}
></div>
</div>
</div>
<div>
<div className="flex items-center justify-between mb-2">
<span className="text-sm">Tablet</span>
<span className="text-sm font-medium">7%</span>
</div>
<div className="w-full bg-muted rounded-full h-2">
<div
className="bg-orange-500 h-2 rounded-full"
style={{ width: "7%" }}
></div>
</div>
</div>
</div>
</CardContent>
</Card>
</div>
{/* Detailed Table */}
<Card>
<CardHeader>
<CardTitle>Detailed Metrics</CardTitle>
</CardHeader>
<CardContent>
<div className="overflow-x-auto">
<table className="w-full">
<thead>
<tr className="border-b">
<th className="text-left py-3 px-4">Date</th>
<th className="text-right py-3 px-4">Views</th>
<th className="text-right py-3 px-4">Visitors</th>
<th className="text-right py-3 px-4">Bounce Rate</th>
<th className="text-right py-3 px-4">Avg. Duration</th>
</tr>
</thead>
<tbody>
<tr className="border-b">
<td className="py-3 px-4">2025-01-15</td>
<td className="text-right py-3 px-4">1,234</td>
<td className="text-right py-3 px-4">987</td>
<td className="text-right py-3 px-4">42.3%</td>
<td className="text-right py-3 px-4">4:32</td>
</tr>
<tr className="border-b">
<td className="py-3 px-4">2025-01-14</td>
<td className="text-right py-3 px-4">1,156</td>
<td className="text-right py-3 px-4">923</td>
<td className="text-right py-3 px-4">43.1%</td>
<td className="text-right py-3 px-4">4:18</td>
</tr>
<tr className="border-b">
<td className="py-3 px-4">2025-01-13</td>
<td className="text-right py-3 px-4">1,098</td>
<td className="text-right py-3 px-4">876</td>
<td className="text-right py-3 px-4">44.5%</td>
<td className="text-right py-3 px-4">4:05</td>
</tr>
</tbody>
</table>
</div>
</CardContent>
</Card>
</Container>
);
}주요 기능
기간 선택
<Select value={period} onValueChange={setPeriod}>
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="기간 선택" />
</SelectTrigger>
<SelectContent>
<SelectItem value="7d">최근 7일</SelectItem>
<SelectItem value="30d">최근 30일</SelectItem>
<SelectItem value="90d">최근 90일</SelectItem>
<SelectItem value="custom">사용자 지정</SelectItem>
</SelectContent>
</Select>PDF 내보내기
import jsPDF from "jspdf";
import html2canvas from "html2canvas";
const exportToPDF = async () => {
const element = document.getElementById("report-content");
const canvas = await html2canvas(element);
const imgData = canvas.toDataURL("image/png");
const pdf = new jsPDF();
pdf.addImage(imgData, "PNG", 10, 10, 190, 0);
pdf.save("analytics-report.pdf");
};차트 통합
Recharts 예제
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend } from "recharts"
const data = [
{ date: "2025-01-01", views: 1200, visitors: 980 },
{ date: "2025-01-02", views: 1350, visitors: 1050 },
// ...
]
<LineChart width={600} height={300} data={data}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="date" />
<YAxis />
<Tooltip />
<Legend />
<Line type="monotone" dataKey="views" stroke="#8884d8" />
<Line type="monotone" dataKey="visitors" stroke="#82ca9d" />
</LineChart>다음 단계
Last updated on