org-network / frontend /src /components /ops /OpsProjectNew.tsx
5minbetter's picture
deploy: initial clean workspace without lfs history
33d9e63
Raw
History Blame Contribute Delete
3.91 kB
/**
* @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>
);
};