| import React from 'react'; | |
| import { motion } from 'framer-motion'; | |
| const ProcessingProgress = ({ progress, isVisible }) => { | |
| if (!isVisible) return null; | |
| const { | |
| current, | |
| total, | |
| status, | |
| fileName, | |
| totalPages, | |
| currentPage, | |
| totalCharacters, | |
| pageCharacters, | |
| phase, | |
| consoleLogs = [] | |
| } = progress; | |
| const percentage = total > 0 ? Math.round((current / total) * 100) : 0; | |
| return ( | |
| <motion.div | |
| className="processing-progress-overlay" | |
| initial={{ opacity: 0 }} | |
| animate={{ opacity: 1 }} | |
| exit={{ opacity: 0 }} | |
| > | |
| <div className="processing-progress-container"> | |
| <div className="progress-content"> | |
| <div className="progress-header"> | |
| <h3>π Luna Processing</h3> | |
| <div className="progress-file"> | |
| π {fileName || 'Processing file...'} | |
| </div> | |
| </div> | |
| <div className="progress-bar-container"> | |
| <div className="progress-bar"> | |
| <motion.div | |
| className="progress-fill" | |
| initial={{ width: 0 }} | |
| animate={{ width: `${percentage}%` }} | |
| transition={{ duration: 0.5, ease: "easeOut" }} | |
| /> | |
| </div> | |
| <div className="progress-percentage">{percentage}%</div> | |
| </div> | |
| <div className="progress-status"> | |
| {status && ( | |
| <motion.div | |
| key={status} | |
| initial={{ opacity: 0, y: 10 }} | |
| animate={{ opacity: 1, y: 0 }} | |
| className="status-text" | |
| > | |
| {status} | |
| </motion.div> | |
| )} | |
| </div> | |
| {totalPages > 1 && ( | |
| <div className="progress-details"> | |
| <div className="progress-counter"> | |
| <span className="counter-current">{currentPage || 0}</span> | |
| <span className="counter-separator">/</span> | |
| <span className="counter-total">{totalPages}</span> | |
| <span className="counter-label">pages</span> | |
| </div> | |
| {totalCharacters > 0 && ( | |
| <div className="progress-stats"> | |
| <div className="stat-item"> | |
| <span className="stat-label">Total Characters:</span> | |
| <span className="stat-value">{totalCharacters.toLocaleString()}</span> | |
| </div> | |
| {pageCharacters > 0 && ( | |
| <div className="stat-item"> | |
| <span className="stat-label">Last Page:</span> | |
| <span className="stat-value">{pageCharacters.toLocaleString()} chars</span> | |
| </div> | |
| )} | |
| </div> | |
| )} | |
| </div> | |
| )} | |
| {consoleLogs.length > 0 && ( | |
| <div className="console-logs"> | |
| <div className="console-header">π Live Process Log</div> | |
| <div className="console-content"> | |
| {consoleLogs.slice(-6).map((log, index) => ( | |
| <div key={index} className="console-line"> | |
| <span className="console-time"> | |
| {new Date(log.timestamp).toLocaleTimeString('th-TH', { | |
| hour12: false, | |
| hour: '2-digit', | |
| minute: '2-digit', | |
| second: '2-digit' | |
| })} | |
| </span> | |
| <span className="console-message">{log.message}</span> | |
| </div> | |
| ))} | |
| </div> | |
| </div> | |
| )} | |
| <div className="processing-animation"> | |
| <div className="processing-dots"> | |
| <div className="dot"></div> | |
| <div className="dot"></div> | |
| <div className="dot"></div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </motion.div> | |
| ); | |
| }; | |
| export default ProcessingProgress; |