Spaces:
Running
Running
| /** | |
| * @license | |
| * SPDX-License-Identifier: Apache-2.0 | |
| */ | |
| import React from 'react'; | |
| import { Project } from '../../types'; | |
| import { projectService } from '../../services/projectService'; | |
| import { Check, AlertCircle } from 'lucide-react'; | |
| import { defaultsService } from '../../services/defaultsService'; | |
| import { ProjectForm, ProjectFormData } from '../common/ProjectForm'; | |
| interface OpsProjectNewProps { | |
| onNavigateHome: () => void; | |
| onSubmitSuccess: (projectId: string) => void; | |
| } | |
| export const OpsProjectNew: React.FC<OpsProjectNewProps> = ({ | |
| onNavigateHome, | |
| onSubmitSuccess, | |
| }) => { | |
| const [error, setError] = React.useState<string | null>(null); | |
| const handleSubmit = async (formData: ProjectFormData) => { | |
| setError(null); | |
| // Validations | |
| if (!formData.title.trim() || !formData.companyName.trim() || !formData.startDate || !formData.endDate) { | |
| setError('프로젝트명, 고객사명, 진단 기간은 필수 입력 항목입니다.'); | |
| return; | |
| } | |
| // Auto generate codes | |
| const cleanKey = formData.companyName.replace(/[^a-zA-Z0-9ㄱ-ㅎㅏ-ㅣ가-힣]/g, ''); | |
| const loginNum = Math.floor(Math.random() * 9000) + 1000; | |
| const surveyLoginId = `survey_${cleanKey || 'audit'}_${loginNum}`; | |
| const codeNum = Math.floor(Math.random() * 900) + 100; | |
| const commonCode = `code_${codeNum}`; | |
| const projectId = `proj_${Date.now()}`; | |
| try { | |
| const systemDefaults = await defaultsService.getDefaults(); | |
| const newProject: Omit<Project, 'created_at' | 'updated_at'> = { | |
| id: projectId, | |
| title: formData.title.trim(), | |
| status: 'draft', // default draft status | |
| start_date: formData.startDate, | |
| end_date: formData.endDate, | |
| max_selections: 5, | |
| anonymous_mode: 'real_name', | |
| survey_login_id: surveyLoginId, | |
| survey_password_hash: '', // Storing raw as hash placeholder for MVP mockup | |
| common_survey_code: commonCode, | |
| common_survey_url: `${window.location.origin}/survey?code=${commonCode}`, | |
| respondent_verification_method: 'employee_id_name', | |
| company_info: { | |
| name: formData.companyName.trim(), | |
| contact_name: formData.contactName.trim(), | |
| contact_email: formData.contactEmail.trim(), | |
| memo: formData.memo.trim(), | |
| }, | |
| questions: systemDefaults.QUESTIONS, | |
| network_types: systemDefaults.NETWORK_TYPES, | |
| employees: [], // empty at first | |
| }; | |
| await projectService.addProject(newProject); | |
| onSubmitSuccess(projectId); | |
| } catch (err) { | |
| console.error(err); | |
| setError('프로젝트 생성 도중 예기치 못한 오류가 발생했습니다.'); | |
| } | |
| }; | |
| return ( | |
| <div className="max-w-3xl mx-auto space-y-6 font-sans antialiased" id="ops-project-new-view"> | |
| {/* Top action nav bar */} | |
| <div className="flex items-center justify-center"> | |
| <div className="text-center"> | |
| <h2 className="text-xl font-bold text-slate-900 uppercase tracking-tight">신규 진단 프로젝트 생성</h2> | |
| <p className="text-sm text-slate-400 mt-0.5"> | |
| 고객사 기본 정보, 네트워크 진단 기간을 등록합니다. | |
| </p> | |
| </div> | |
| </div> | |
| {error && ( | |
| <div className="flex items-start gap-2 p-3 bg-red-50 border border-red-100 text-red-800 rounded-lg text-sm font-semibold"> | |
| <AlertCircle className="w-4 h-4 text-red-500 shrink-0 mt-0.5" /> | |
| <span>{error}</span> | |
| </div> | |
| )} | |
| <div className="bg-white p-6 rounded-xl border border-slate-100" id="new-project-basic-config-panel"> | |
| <ProjectForm | |
| onSubmit={handleSubmit} | |
| submitButtonText="프로젝트 생성" | |
| submitIcon={<Check className="w-4 h-4" />} | |
| onCancel={onNavigateHome} | |
| cancelButtonText="취소" | |
| /> | |
| </div> | |
| </div> | |
| ); | |
| }; | |