/** * @license * SPDX-License-Identifier: Apache-2.0 */ import React from 'react'; import { Project } from '../../types'; import { Button } from '../common/Button'; import { Badge } from '../common/Badge'; import { projectService } from '../../services/projectService'; import { Modal } from '../common/Modal'; import { LayoutDashboard, Settings, Share2, Home, ExternalLink, LogOut, Menu, Users, HelpCircle, Play, Pause, } from 'lucide-react'; interface OpsLayoutProps { project?: Project | null; onUpdateProject?: (updated: Project) => void; activeTab?: 'dashboard' | 'basic' | 'organization' | 'questions' | 'distribution'; onNavigateTab?: (tab: 'dashboard' | 'basic' | 'organization' | 'questions' | 'distribution') => void; onNavigateHome?: () => void; onLogout: () => void; children: React.ReactNode; } export const OpsLayout: React.FC = ({ project, onUpdateProject, activeTab, onNavigateTab, onNavigateHome, onLogout, children, }) => { const [mobileMenuOpen, setMobileMenuOpen] = React.useState(false); const isProjectPage = !!project; const [adminId, setAdminId] = React.useState('Admin'); // Modal states const [modalOpen, setModalOpen] = React.useState(false); const [modalTitle, setModalTitle] = React.useState(''); const [modalMessage, setModalMessage] = React.useState(''); const [modalConfirmAction, setModalConfirmAction] = React.useState<(() => void) | null>(null); const [isAlert, setIsAlert] = React.useState(false); React.useEffect(() => { if (typeof window !== 'undefined') { const storedId = localStorage.getItem('stateless_ops_user_id'); if (storedId) { setAdminId(storedId); } } }, []); // Status badge styling const getStatusBadge = (status: Project['status']) => { switch (status) { case 'draft': return ( 초안 (Draft) ); case 'collecting': return ( 수집 중 (Collecting) ); case 'closed': return ( 마감됨 (Closed) ); default: return null; } }; // Response rates calculations const totalEmployees = project?.employees.length || 0; const submittedCount = project?.employees.filter((e) => e.response_status === 'submitted').length || 0; const responseRate = totalEmployees > 0 ? Math.round((submittedCount / totalEmployees) * 100) : 0; const handleToggleStatus = () => { if (!project) return; const nextStatus: Project['status'] = project.status === 'collecting' ? 'closed' : 'collecting'; const msg = nextStatus === 'closed' ? '설문을 마감하시겠습니까? 마감 시 임직원들은 더 이상 설문 페이지에 접속할 수 없습니다.' : '설문 수집을 재개하시겠습니까?'; setModalTitle('프로젝트 상태 변경'); setModalMessage(msg); setIsAlert(false); setModalConfirmAction(() => async () => { setModalOpen(false); try { const updated = await projectService.updateProjectStatus(project.id, nextStatus); if (updated) { onUpdateProject?.(updated); // Show success modal setModalTitle('알림'); setModalMessage('프로젝트 수집 상태가 변경되었습니다.'); setIsAlert(true); setModalConfirmAction(null); setModalOpen(true); } } catch (err: any) { // Show error modal setModalTitle('오류'); setModalMessage(`수집 상태 변경 실패: ${err.message}`); setIsAlert(true); setModalConfirmAction(null); setModalOpen(true); } }); setModalOpen(true); }; return (
{/* Top Navbar */}
{project && ( )}
{adminId}
{/* Main Body */}
{/* Sidebar Left */} {project && ( )} {/* Main Content Pane */}
{children}
{/* Footer */}
© 2026 시앤피컨설팅 주식회사. All rights reserved.
{/* Backdrop for mobile sidebar drawer */} {mobileMenuOpen && (
setMobileMenuOpen(false)} className="fixed inset-0 z-20 bg-slate-900/10 backdrop-blur-xs lg:hidden" id="ops-sidebar-mobile-backdrop" /> )} {/* Common Modal for dialogs */} setModalOpen(false)} title={modalTitle} showCloseButton={true} footerActions={ isAlert ? ( ) : (
) } >

{modalMessage}

); };