import React, { useState, useEffect } from 'react';
import {
StyleSheet,
View,
Text,
TouchableOpacity,
ActivityIndicator,
ScrollView,
useWindowDimensions,
} from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { BarChart } from 'react-native-gifted-charts';
import StatsPeriodControls from '../components/StatsPeriodControls';
import UploadModal from '../components/UploadModal';
import usePlantStats from '../hooks/usePlantStats';
export default function PlantDetailScreen({ route, navigation }) {
const { plant } = route.params;
const [period, setPeriod] = useState('today');
const [uploadVisible, setUploadVisible] = useState(false);
const { width } = useWindowDimensions();
const [currentDate, setCurrentDate] = useState(new Date());
const { chartData, loading, error, reload: fetchStats, todayData } = usePlantStats(
plant,
period,
currentDate,
);
// 탭 변경 시 날짜 초기화
useEffect(() => {
setCurrentDate(new Date());
}, [period]);
// 날짜 이동
const moveDate = (direction) => {
const newDate = new Date(currentDate);
if (period === 'today') {
newDate.setDate(newDate.getDate() + direction);
} else if (period === 'day') {
// 일간 탭: '월' 단위 이동
newDate.setMonth(newDate.getMonth() + direction);
} else if (period === 'month') {
// 월간 탭: '년' 단위 이동
newDate.setFullYear(newDate.getFullYear() + direction);
} else if (period === 'year') {
// 연간 탭: '년' 단위 이동 (일단 1년씩)
newDate.setFullYear(newDate.getFullYear() + direction);
}
setCurrentDate(newDate);
};
// 날짜 포맷팅 (YYYY년 MM월 DD일 등)
const formatDateDisplay = () => {
const y = currentDate.getFullYear();
const m = currentDate.getMonth() + 1;
const d = currentDate.getDate();
if (period === 'today') return `${y}년 ${m}월 ${d}일`;
if (period === 'day') return `${y}년 ${m}월`;
if (period === 'month') return `${y}년`;
if (period === 'year') return `${y - 4}년 ~ ${y}년`;
return `${y}년 기준`;
};
// 툴팁 렌더링 (커스텀)
const renderTooltip = (item) => {
return (
{item.value.toFixed(1)}{period === 'today' ? 'kW' : 'kWh'}
);
};
// 총 발전량 계산
const getTotalGeneration = () => {
return chartData.reduce((sum, item) => sum + (item.value || 0), 0);
};
const chartWidth = Math.min(width - 60, 600);
// 막대 너비 및 간격 계산
let barWidth = 10;
let spacing = 10;
if (period === 'today') {
// 화면 꽉 차게 (25개 항목: 0~24시) - 스크롤 없애기 위함
const availableWidth = chartWidth - 20;
const itemWidth = availableWidth / 25;
barWidth = Math.max(4, itemWidth * 0.6); // 60% 바
spacing = Math.max(2, itemWidth * 0.4); // 40% 여백
} else if (period === 'year') {
barWidth = 40;
spacing = 20;
} else if (period === 'month') {
barWidth = 24;
spacing = 12;
} else { // day
barWidth = 10;
spacing = 3;
}
return (
{/* 헤더 */}
navigation.goBack()}>
← 뒤로
{plant.name}
{/* 오늘 실시간 현황 카드 (today 탭일 때만) */}
{period === 'today' && todayData && (
⚡ 실시간 발전 현황
갱신: {todayData.updatedAt}
{todayData.currentKw.toFixed(1)}
현재 출력 (kW)
{todayData.todayKwh.toFixed(1)}
금일 발전량 (kWh)
)}
{/* 차트 영역 */}
📊 {period === 'today' ? '시간대별 출력' : '발전량 추이'} ({formatDateDisplay()})
막대를 터치하면 상세 정보
{loading ? (
데이터 로딩 중...
) : error ? (
⚠️ 데이터를 불러올 수 없습니다
{error}
다시 시도
) : chartData.length === 0 ? (
📭 표시할 데이터가 없습니다
{period === 'today' ? '크롤러가 데이터를 수집하면 표시됩니다' : '엑셀 파일을 업로드해 주세요'}
) : (
d.value || 0)) * 1.2 || 10} // 툴팁 공간 확보 (20%)
width={chartWidth}
height={220}
barWidth={barWidth}
spacing={spacing}
barBorderRadius={4}
frontColor="#3B82F6"
yAxisThickness={1}
xAxisThickness={1}
yAxisColor="#E5E7EB"
xAxisColor="#E5E7EB"
yAxisTextStyle={{ color: '#6B7280', fontSize: 10 }}
xAxisLabelTextStyle={{ color: '#6B7280', fontSize: 9 }}
noOfSections={5}
hideRules={false}
rulesColor="#F3F4F6"
showValuesAsTopLabel={false}
isAnimated
yAxisSuffix={period === 'today' ? '' : ''}
renderTooltip={renderTooltip}
/>
)}
{/* 통계 요약 (today 제외) */}
{period !== 'today' && (
📈 통계 요약
총 발전량
{getTotalGeneration().toLocaleString(undefined, { maximumFractionDigits: 1 })}
kWh
데이터 수
{chartData.length}
건
설비 용량
{plant.capacity || '-'}
kW
)}
{/* 업로드 버튼 */}
setUploadVisible(true)}
>
📂 과거 엑셀 데이터 업로드
* 일간 또는 월간 형식을 선택할 수 있습니다
setUploadVisible(false)}
plantId={plant.id}
onUploadSuccess={fetchStats}
/>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F3F4F6',
},
header: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
backgroundColor: '#1E40AF',
paddingHorizontal: 16,
paddingVertical: 16,
},
backButton: {
paddingVertical: 8,
paddingHorizontal: 4,
},
backButtonText: {
color: '#FFFFFF',
fontSize: 16,
fontWeight: '500',
},
headerTitle: {
fontSize: 18,
fontWeight: 'bold',
color: '#FFFFFF',
flex: 1,
textAlign: 'center',
},
headerSpacer: {
width: 60,
},
content: {
flex: 1,
},
contentContainer: {
padding: 16,
gap: 16,
},
// Today Card
todayCard: {
backgroundColor: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
backgroundColor: '#1E40AF',
borderRadius: 16,
padding: 20,
shadowColor: '#1E40AF',
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.3,
shadowRadius: 8,
elevation: 6,
},
todayHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 16,
},
todayTitle: {
fontSize: 16,
fontWeight: '700',
color: '#FFFFFF',
},
todayTime: {
fontSize: 12,
color: '#93C5FD',
},
todayStats: {
flexDirection: 'row',
alignItems: 'center',
},
todayStat: {
flex: 1,
alignItems: 'center',
},
todayStatValue: {
fontSize: 36,
fontWeight: 'bold',
color: '#FFFFFF',
},
todayStatLabel: {
fontSize: 12,
color: '#93C5FD',
marginTop: 4,
},
todayDivider: {
width: 1,
height: 50,
backgroundColor: 'rgba(255,255,255,0.3)',
marginHorizontal: 16,
},
// Chart Section
chartSection: {
backgroundColor: '#FFFFFF',
borderRadius: 16,
padding: 16,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 8,
elevation: 4,
},
chartHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 16,
},
sectionTitle: {
fontSize: 16,
fontWeight: '700',
color: '#1F2937',
},
chartHint: {
fontSize: 11,
color: '#9CA3AF',
},
chartContainer: {
alignItems: 'center',
paddingVertical: 10,
},
loadingContainer: {
height: 200,
justifyContent: 'center',
alignItems: 'center',
},
loadingText: {
marginTop: 12,
color: '#6B7280',
fontSize: 14,
},
errorContainer: {
height: 200,
justifyContent: 'center',
alignItems: 'center',
},
errorText: {
fontSize: 16,
color: '#EF4444',
marginBottom: 8,
},
errorDetail: {
fontSize: 12,
color: '#6B7280',
marginBottom: 16,
},
retryButton: {
backgroundColor: '#3B82F6',
paddingHorizontal: 24,
paddingVertical: 10,
borderRadius: 8,
},
retryButtonText: {
color: '#FFFFFF',
fontWeight: '600',
},
emptyContainer: {
height: 200,
justifyContent: 'center',
alignItems: 'center',
},
emptyText: {
fontSize: 18,
color: '#6B7280',
marginBottom: 8,
},
emptySubtext: {
fontSize: 14,
color: '#9CA3AF',
},
// Summary Section
summarySection: {
backgroundColor: '#FFFFFF',
borderRadius: 16,
padding: 16,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 8,
elevation: 4,
},
summaryCards: {
flexDirection: 'row',
gap: 12,
marginTop: 12,
},
summaryCard: {
flex: 1,
backgroundColor: '#F0F9FF',
borderRadius: 12,
padding: 16,
alignItems: 'center',
},
summaryLabel: {
fontSize: 12,
color: '#6B7280',
marginBottom: 4,
},
summaryValue: {
fontSize: 24,
fontWeight: 'bold',
color: '#1E40AF',
},
summaryUnit: {
fontSize: 12,
color: '#6B7280',
marginTop: 2,
},
// Upload Section
uploadSection: {
alignItems: 'center',
paddingVertical: 8,
},
uploadButton: {
backgroundColor: '#10B981',
paddingHorizontal: 32,
paddingVertical: 16,
borderRadius: 12,
width: '100%',
alignItems: 'center',
shadowColor: '#10B981',
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.3,
shadowRadius: 8,
elevation: 6,
},
uploadButtonText: {
color: '#FFFFFF',
fontSize: 16,
fontWeight: '700',
},
uploadHint: {
marginTop: 12,
fontSize: 12,
color: '#9CA3AF',
},
});