- 발송 통계 페이지 (StatisticsPage): 4개 통계 카드, 월간 추이 라인 차트, 플랫폼별 도넛 차트, 시간대별 바 차트, 최근 이력 테이블, 오픈율 Top5 - 발송 이력 페이지 (StatisticsHistoryPage): 검색/서비스/상태/날짜 필터, 발송 이력 테이블, 행 클릭 슬라이드 패널 (발송 상세), 페이지네이션 - 타입 정의 + 목 데이터 15건 (types.ts) - 브레드크럼 그룹 라벨 처리 (발송 관리 > 발송 통계/발송 이력) - 날짜 필터 기본값: 오늘 기준 1달 전 ~ 오늘 - 대시보드와 카드/차트 스타일 통일 - 메시지 목록 연동: 슬라이드 패널에서 messageId 쿼리 파라미터로 이동 Closes #23
47 lines
1.7 KiB
TypeScript
47 lines
1.7 KiB
TypeScript
import type { OpenRateRank } from "../types";
|
|
|
|
interface OpenRateTop5Props {
|
|
data: OpenRateRank[];
|
|
}
|
|
|
|
/** 오픈율 Top 5 랭킹 */
|
|
export default function OpenRateTop5({ data }: OpenRateTop5Props) {
|
|
return (
|
|
<div className="lg:col-span-1 bg-white rounded-xl shadow-sm border border-gray-200 p-6 flex flex-col">
|
|
<h2 className="text-base font-bold text-[#0f172a] mb-6">오픈율 Top 5</h2>
|
|
<div className="flex-1 flex flex-col justify-between">
|
|
{data.map((item) => {
|
|
const isTop2 = item.rank <= 2;
|
|
return (
|
|
<div key={item.rank} className="flex items-center gap-3">
|
|
<span
|
|
className={`text-xs font-bold size-6 rounded-full flex items-center justify-center flex-shrink-0 ${
|
|
isTop2
|
|
? "text-primary bg-blue-50"
|
|
: "text-gray-500 bg-gray-100"
|
|
}`}
|
|
>
|
|
{item.rank}
|
|
</span>
|
|
<div className="flex-1 min-w-0">
|
|
<p className="text-sm font-medium text-gray-900 truncate">{item.template}</p>
|
|
<div className="mt-1.5 h-2 rounded-full bg-gray-100 overflow-hidden">
|
|
<div
|
|
className={`h-full rounded-full ${
|
|
isTop2 ? "bg-primary" : item.rank === 3 ? "bg-blue-300" : "bg-blue-200"
|
|
}`}
|
|
style={{ width: `${item.rate}%` }}
|
|
/>
|
|
</div>
|
|
</div>
|
|
<span className="text-sm font-bold text-gray-900 flex-shrink-0">
|
|
{item.rate}%
|
|
</span>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|