/** * UploadModal.js - 과거 발전 데이터 엑셀 업로드 모달 */ import React, { useState } from 'react'; // Force Update Check import { Modal, View, Text, TouchableOpacity, StyleSheet, ActivityIndicator, Alert, } from 'react-native'; import * as DocumentPicker from 'expo-document-picker'; const API_URL = 'https://solorpower.dadot.net'; export default function UploadModal({ visible, onClose, plantId, onUploadSuccess }) { const [uploading, setUploading] = useState(false); const [selectedFile, setSelectedFile] = useState(null); const [uploadType, setUploadType] = useState('daily'); // 'daily' | 'monthly' // 파일 선택 const pickDocument = async () => { try { const result = await DocumentPicker.getDocumentAsync({ type: [ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // .xlsx 'application/vnd.ms-excel', // .xls ], copyToCacheDirectory: true, }); if (!result.canceled && result.assets && result.assets.length > 0) { setSelectedFile(result.assets[0]); } } catch (error) { Alert.alert('오류', '파일 선택 중 오류가 발생했습니다.'); } }; // 업로드 실행 const handleUpload = async () => { if (!selectedFile) { Alert.alert('알림', '먼저 파일을 선택해주세요.'); return; } if (!plantId) { Alert.alert('알림', '발전소를 선택해주세요.'); return; } setUploading(true); try { const formData = new FormData(); // 파일 추가 formData.append('file', { uri: selectedFile.uri, name: selectedFile.name, type: selectedFile.mimeType || 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', }); // uploadType에 따라 엔드포인트 분기 const endpoint = uploadType === 'daily' ? `/plants/${plantId}/upload` : `/plants/${plantId}/upload/monthly`; console.log(`🚀 Uploading ${uploadType} data`); console.log(" URL:", `${API_URL}${endpoint}`); const response = await fetch(`${API_URL}${endpoint}`, { method: 'POST', body: formData, headers: { 'Content-Type': 'multipart/form-data', }, }); const result = await response.json(); if (response.ok) { Alert.alert('성공', result.message || '업로드가 완료되었습니다.'); setSelectedFile(null); onUploadSuccess?.(); onClose(); } else { Alert.alert('오류', result.detail || '업로드에 실패했습니다.'); } } catch (error) { Alert.alert('오류', `업로드 중 오류가 발생했습니다: ${error.message}`); } finally { setUploading(false); } }; // 모달 닫기 const handleClose = () => { setSelectedFile(null); setUploadType('daily'); onClose(); }; return ( {/* 헤더 */} 📂 과거 데이터 업로드 {/* 타입 선택 탭 */} setUploadType('daily')} > 일간 (Daily) setUploadType('monthly')} > 월간 (Monthly) {/* 안내 */} {uploadType === 'daily' ? "필수 컬럼: date (날짜), generation (발전량) 또는 year, month, day, kwh" : "필수 컬럼: year (연도), month (월), kwh (발전량)\n* 합계/평균 행 자동 제외" } {/* 발전소 ID 표시 */} 발전소 ID: {plantId || '선택 안됨'} {/* 파일 선택 */} {selectedFile ? '📄 ' + selectedFile.name : '📁 엑셀 파일 선택 (.xlsx)'} {/* 선택된 파일 정보 */} {selectedFile && ( 크기: {(selectedFile.size / 1024).toFixed(1)} KB )} {/* 업로드 버튼 */} {uploading ? ( ) : ( {uploadType === 'daily' ? '일간 데이터 업로드' : '월간 데이터 업로드'} )} {/* 취소 버튼 */} 취소 ); } const styles = StyleSheet.create({ overlay: { flex: 1, backgroundColor: 'rgba(0, 0, 0, 0.5)', justifyContent: 'center', alignItems: 'center', padding: 20, }, modalContainer: { backgroundColor: '#FFFFFF', borderRadius: 16, padding: 24, width: '100%', maxWidth: 400, shadowColor: '#000', shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.25, shadowRadius: 16, elevation: 8, }, header: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16, }, title: { fontSize: 20, fontWeight: '700', color: '#1F2937', }, closeButton: { padding: 4, }, closeButtonText: { fontSize: 20, color: '#6B7280', }, description: { fontSize: 14, color: '#6B7280', marginBottom: 16, lineHeight: 20, }, infoBox: { flexDirection: 'row', backgroundColor: '#F3F4F6', padding: 12, borderRadius: 8, marginBottom: 16, }, infoLabel: { fontSize: 14, color: '#6B7280', marginRight: 8, }, infoValue: { fontSize: 14, fontWeight: '600', color: '#1F2937', }, fileButton: { backgroundColor: '#E5E7EB', padding: 16, borderRadius: 8, alignItems: 'center', marginBottom: 8, borderWidth: 2, borderColor: '#D1D5DB', borderStyle: 'dashed', }, fileButtonText: { fontSize: 16, color: '#374151', }, fileInfo: { alignItems: 'center', marginBottom: 16, }, fileInfoText: { fontSize: 12, color: '#6B7280', }, uploadButton: { backgroundColor: '#3B82F6', padding: 16, borderRadius: 8, alignItems: 'center', marginBottom: 8, }, uploadButtonDisabled: { backgroundColor: '#9CA3AF', }, uploadButtonText: { fontSize: 16, fontWeight: '600', color: '#FFFFFF', }, cancelButton: { padding: 12, alignItems: 'center', }, cancelButtonText: { fontSize: 14, color: '#6B7280', }, });