/** * 봇 카드 컴포넌트 */ import { memo } from 'react'; import { motion } from 'framer-motion'; import { Youtube, Play, Square, RefreshCw, Download } from 'lucide-react'; // X 아이콘 컴포넌트 export const XIcon = ({ size = 20, fill = 'currentColor' }) => ( ); // Meilisearch 아이콘 컴포넌트 export const MeilisearchIcon = ({ size = 20 }) => ( ); /** * @param {Object} props * @param {Object} props.bot - 봇 데이터 * @param {number} props.index - 인덱스 (애니메이션용) * @param {boolean} props.isInitialLoad - 첫 로드 여부 * @param {string|null} props.syncing - 동기화 중인 봇 ID * @param {Object} props.statusInfo - 상태 정보 (text, color, bg, dot) * @param {Function} props.onSync - 동기화 핸들러 * @param {Function} props.onToggle - 토글 핸들러 * @param {Function} props.onAnimationComplete - 애니메이션 완료 핸들러 * @param {Function} props.formatTime - 시간 포맷 함수 * @param {Function} props.formatInterval - 간격 포맷 함수 */ const BotCard = memo(function BotCard({ bot, index, isInitialLoad, syncing, statusInfo, onSync, onToggle, onAnimationComplete, formatTime, formatInterval, }) { return ( {/* 상단: 이름 + 상태 */} {bot.name} {bot.last_check_at ? formatTime(bot.last_check_at) : '대기 중'} {statusInfo.text} {/* 통계 */} {bot.schedules_added || 0} 총 추가 0 ? 'text-green-600' : 'text-gray-400'}`}> +{bot.last_added_count || 0} 최근 {formatInterval(bot.check_interval)} 간격 {/* 오류 메시지 */} {bot.status === 'error' && bot.error_message && ( {bot.error_message} )} {/* 액션 버튼 */} onSync(bot.id)} disabled={syncing === bot.id} className="flex-1 flex items-center justify-center gap-1.5 px-4 py-2.5 text-sm font-medium text-gray-600 hover:bg-gray-50 transition-colors disabled:opacity-50 border-r border-gray-100" > {syncing === bot.id ? ( <> 동기화 중 > ) : ( <> 전체 동기화 > )} onToggle(bot.id, bot.status, bot.name)} className={`flex items-center justify-center gap-1.5 px-4 py-2.5 text-sm font-medium transition-colors ${ bot.status === 'running' ? 'text-gray-600 hover:bg-gray-50' : 'text-green-600 hover:bg-green-50' }`} > {bot.status === 'running' ? ( <> 정지 > ) : ( <> 시작 > )} ); }); export default BotCard;
{bot.last_check_at ? formatTime(bot.last_check_at) : '대기 중'}