// === 수동 상품 등록 === // ISVM 없이 사용자가 직접 정보 입력 → 네이버 스토어에 등록. // 기존 naverRegisterFromTemplate 재사용 (카테고리/원산지/인증 메타는 매장 라이브 상품에서 자동 참조). function ManualRegisterScreen({ products }) { const isConfigured = window.API.naverConfigured(); // 폼 state const [name, setName] = useState(""); const [salePrice, setSalePrice] = useState(""); const [stock, setStock] = useState(""); const [sellerCode, setSellerCode] = useState(""); const [leafCategoryId, setLeafCategoryId] = useState(""); const [descText, setDescText] = useState(""); // 이미지: [{ file, preview, naverUrl? }] const [images, setImages] = useState([]); const [mainIdx, setMainIdx] = useState(0); // 등록 진행 const [registering, setRegistering] = useState(false); const [progress, setProgress] = useState(null); // { done, total, label } const [result, setResult] = useState(null); const [confirmOpen, setConfirmOpen] = useState(false); // template 자동 선택 (카테고리/원산지/인증 메타용) const templateProductId = products.find(p => p.originProductNo)?.originProductNo; const fileInputRef = useRef(null); const handleFiles = (fileList) => { if (!fileList || fileList.length === 0) return; const next = []; Array.from(fileList).forEach(file => { if (!file.type.startsWith("image/")) return; next.push({ id: Date.now() + "-" + Math.random().toString(36).slice(2, 8), file, preview: URL.createObjectURL(file), }); }); setImages(prev => [...prev, ...next].slice(0, 10)); // 최대 10장 (대표 1 + 추가 9) }; const removeImage = (id) => { setImages(prev => { const next = prev.filter(it => it.id !== id); const removedIdx = prev.findIndex(it => it.id === id); // 메인 이미지 인덱스 조정 if (removedIdx === mainIdx) setMainIdx(0); else if (removedIdx < mainIdx) setMainIdx(i => Math.max(0, i - 1)); return next; }); }; const setAsMain = (idx) => setMainIdx(idx); const resetForm = () => { images.forEach(it => URL.revokeObjectURL(it.preview)); setName(""); setSalePrice(""); setStock(""); setSellerCode(""); setLeafCategoryId(""); setDescText(""); setImages([]); setMainIdx(0); setProgress(null); setResult(null); }; const validate = () => { if (!name.trim()) return "상품명을 입력하세요"; if (!parseInt(salePrice)) return "판매가를 입력하세요"; if (parseInt(salePrice) % 10 !== 0) return "판매가는 10원 단위여야 합니다"; if (!parseInt(stock) && parseInt(stock) !== 0) return "재고를 입력하세요 (0 이상)"; if (images.length === 0) return "이미지를 1장 이상 추가하세요"; if (!templateProductId) return "매장에 라이브 상품이 1개 이상 있어야 등록 가능 (카테고리/원산지 참조용)"; return null; }; const doRegister = async () => { const err = validate(); if (err) { toast(err); return; } setConfirmOpen(false); setRegistering(true); setResult(null); try { // 메인 이미지를 첫 번째로 정렬 const ordered = [images[mainIdx], ...images.filter((_, i) => i !== mainIdx)]; // 순차 업로드 const uploadedUrls = []; setProgress({ done: 0, total: ordered.length, label: "이미지 업로드 중" }); for (let i = 0; i < ordered.length; i++) { try { const url = await window.API.naverUploadImageFile(ordered[i].file); uploadedUrls.push(url); } catch (e) { console.warn("[manual upload " + (i + 1) + "/" + ordered.length + " 실패]", e.message); } setProgress({ done: i + 1, total: ordered.length, label: "이미지 업로드 중" }); } if (uploadedUrls.length === 0) throw new Error("모든 이미지 업로드 실패"); // 상세설명 HTML — 사용자 입력 텍스트 + 모든 이미지를 SmartEditor 형식으로 let detailHtml = ""; const cleanedDesc = (descText || "").replace(/[<>]/g, "").trim(); if (cleanedDesc) { const escaped = cleanedDesc.split("\n").map(line => `
${line || " "}
`).join(""); detailHtml = `${line || " "}
`).join("")}ISVM 없이 직접 정보 입력해서 네이버 스마트스토어에 등록합니다 · 카테고리/원산지/인증 메타는 매장의 라이브 상품에서 자동 참조 · 배송/A&S는 API 설정의 기본값 사용
{result.response.originProductNo}