- lottoUtils.jsx: 공통 유틸·상수 추출 (Ball, NumberRow, 통계 헬퍼 등) - hooks/useLottoData.js: 핵심 데이터 로드 (최신회차, 통계, 시뮬레이션, 리포트) - hooks/usePurchases.js: 구매 기록 CRUD - hooks/useManualRecommend.js: 수동 추천 + 히스토리 - components/: MetricBlock, FrequencyChart, PerformanceBanner, ConfidenceRing, CombinedRecommendPanel, ReportPanel, PersonalAnalysisPanel, PurchasePanel 분리 - getReport import 누락 버그 수정 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
60 lines
2.7 KiB
JavaScript
60 lines
2.7 KiB
JavaScript
import React from 'react';
|
|
import { toBucketEntries } from '../lottoUtils';
|
|
|
|
const MetricBlock = ({ title, metrics }) => {
|
|
if (!metrics) return null;
|
|
const buckets = toBucketEntries(metrics);
|
|
const maxBucket = buckets.length ? Math.max(...buckets.map(([, v]) => Number(v) || 0), 1) : 1;
|
|
const odd = Number(metrics.odd) || 0;
|
|
const even = Number(metrics.even) || 0;
|
|
const totalOE = odd + even || 1;
|
|
const oddPct = (odd / totalOE) * 100;
|
|
|
|
return (
|
|
<div className="lotto-metrics">
|
|
<div className="lotto-metrics__head">
|
|
<p className="lotto-metrics__title">{title}</p>
|
|
<span className="lotto-metrics__sum">총 출현 횟수 {metrics.sum ?? '-'}</span>
|
|
</div>
|
|
<div className="lotto-metric-cards">
|
|
<div className="lotto-metric-card">
|
|
<p className="lotto-metric-card__label">최소 출현</p>
|
|
<p className="lotto-metric-card__value">{metrics.min ?? '-'}</p>
|
|
</div>
|
|
<div className="lotto-metric-card">
|
|
<p className="lotto-metric-card__label">최대 출현</p>
|
|
<p className="lotto-metric-card__value">{metrics.max ?? '-'}</p>
|
|
</div>
|
|
<div className="lotto-metric-card">
|
|
<p className="lotto-metric-card__label">출현 편차</p>
|
|
<p className="lotto-metric-card__value">{metrics.range ?? '-'}</p>
|
|
</div>
|
|
</div>
|
|
<div className="lotto-odd-even">
|
|
<div className="lotto-odd-even__labels">
|
|
<span>홀 {odd}</span><span>짝 {even}</span>
|
|
</div>
|
|
<div className="lotto-odd-even__bar" aria-hidden>
|
|
<span className="lotto-odd-even__odd" style={{ width: `${oddPct}%` }} />
|
|
<span className="lotto-odd-even__even" style={{ width: `${100 - oddPct}%` }} />
|
|
</div>
|
|
</div>
|
|
{buckets.length ? (
|
|
<div className="lotto-buckets">
|
|
{buckets.map(([label, value]) => (
|
|
<div key={label} className="lotto-bucket">
|
|
<span className="lotto-bucket__label">{label}</span>
|
|
<div className="lotto-bucket__bar" aria-hidden>
|
|
<span style={{ width: `${((Number(value) || 0) / maxBucket) * 100}%` }} />
|
|
</div>
|
|
<span className="lotto-bucket__value">{value}</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
) : null}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default MetricBlock;
|