// ChemiFactory MES - Customer Management Frontend Logic const API_BASE = "/customers"; let allCustomers = []; let selectedCustomerId = null; document.addEventListener("DOMContentLoaded", () => { initEvents(); fetchCustomers(); }); // APIs Integration async function fetchCustomers() { try { const res = await fetch(`${API_BASE}/`); if (!res.ok) throw new Error("Failed to fetch customers"); allCustomers = await res.json(); renderCustomerList(allCustomers); } catch (err) { console.error(err); showListError(); } } async function showCustomerDetail(id) { try { selectedCustomerId = id; const res = await fetch(`${API_BASE}/${id}`); if (!res.ok) throw new Error("Failed to fetch customer details"); const data = await res.json(); renderCustomerDetail(data); } catch (err) { console.error(err); alert("고객사 정보를 상세히 불러오지 못했습니다."); } } // Render Lists function renderCustomerList(list) { const tbody = document.getElementById("customer-list-body"); tbody.innerHTML = ""; if (list.length === 0) { tbody.innerHTML = `등록된 고객사가 없습니다.`; return; } list.forEach(cust => { const tr = document.createElement("tr"); if (selectedCustomerId === cust.id) tr.className = "active-row"; tr.innerHTML = ` ${cust.name_kr} ${cust.contact_number || "-"} ${cust.business_registration_number || "-"} `; tr.addEventListener("click", () => { document.querySelectorAll("#customer-list-body tr").forEach(el => el.classList.remove("active-row")); tr.classList.add("active-row"); showCustomerDetail(cust.id); }); tbody.appendChild(tr); }); } function showListError() { const tbody = document.getElementById("customer-list-body"); tbody.innerHTML = `데이터 통신에 실패했습니다. DB 작동을 확인하십시오.`; } function renderCustomerDetail(data) { // Show details card, hide placeholder document.getElementById("customer-placeholder-card").style.display = "none"; document.getElementById("customer-detail-card").style.display = "block"; const cust = data.customer; document.getElementById("detail-name-kr").innerText = cust.name_kr; document.getElementById("detail-name-en").innerText = cust.name_en || ""; document.getElementById("detail-brn").innerText = cust.business_registration_number || "-"; document.getElementById("detail-contact").innerText = cust.contact_number || "-"; document.getElementById("detail-address").innerText = cust.address || "-"; // Bind Contacts renderContactsList(data.contacts || []); // Bind Sales Activities renderActivitiesList(data.salesActivities || []); } function renderContactsList(contacts) { const tbody = document.getElementById("contact-list-body"); tbody.innerHTML = ""; if (contacts.length === 0) { tbody.innerHTML = `등록된 담당자가 없습니다.`; return; } contacts.forEach(c => { const tr = document.createElement("tr"); tr.innerHTML = ` ${c.name} ${c.position || "-"} ${c.work_location ? `(${c.work_location})` : ""} ${c.phone_number || "-"} ${c.email || "-"} `; tbody.appendChild(tr); }); } function renderActivitiesList(activities) { const tbody = document.getElementById("activity-list-body"); tbody.innerHTML = ""; if (activities.length === 0) { tbody.innerHTML = `영업 활동 내역이 없습니다.`; return; } // Sort by date descending activities.sort((a, b) => new Date(b.activity_date) - new Date(a.activity_date)); activities.forEach(act => { const tr = document.createElement("tr"); tr.innerHTML = ` ${act.activity_date} ${act.activity_type} ${act.memo} `; tbody.appendChild(tr); }); } // Event Bindings function initEvents() { // Search Filter document.getElementById("search-customer").addEventListener("input", (e) => { const query = e.target.value.toLowerCase(); const filtered = allCustomers.filter(c => c.name_kr.toLowerCase().includes(query) || (c.name_en && c.name_en.toLowerCase().includes(query)) || (c.business_registration_number && c.business_registration_number.includes(query)) ); renderCustomerList(filtered); }); // Tab Toggle document.querySelectorAll(".tab-btn").forEach(btn => { btn.addEventListener("click", () => { document.querySelectorAll(".tab-btn").forEach(b => b.classList.remove("active")); document.querySelectorAll(".tab-content").forEach(tc => tc.classList.remove("active")); btn.classList.add("active"); document.getElementById(btn.dataset.tab).classList.add("active"); }); }); // Modals Control const modals = ["customer-modal", "contact-modal", "activity-modal"]; modals.forEach(mId => { const modal = document.getElementById(mId); modal.querySelectorAll(".close-btn, .close-modal-btn").forEach(btn => { btn.addEventListener("click", () => modal.style.display = "none"); }); }); // Add Customer document.getElementById("btn-add-customer").addEventListener("click", () => { document.getElementById("customer-form").reset(); document.getElementById("customer-id").value = ""; document.getElementById("customer-modal-title").innerText = "고객사 등록"; document.getElementById("customer-modal").style.display = "flex"; }); document.getElementById("customer-form").addEventListener("submit", handleCustomerSubmit); // Edit & Delete Customer document.getElementById("btn-edit-customer").addEventListener("click", () => { const activeCust = allCustomers.find(c => c.id === selectedCustomerId); if (!activeCust) return; document.getElementById("customer-id").value = activeCust.id; document.getElementById("cust-name-kr").value = activeCust.name_kr; document.getElementById("cust-name-en").value = activeCust.name_en || ""; document.getElementById("cust-brn").value = activeCust.business_registration_number || ""; document.getElementById("cust-contact").value = activeCust.contact_number || ""; document.getElementById("cust-address").value = activeCust.address || ""; document.getElementById("customer-modal-title").innerText = "고객사 정보 수정"; document.getElementById("customer-modal").style.display = "flex"; }); document.getElementById("btn-delete-customer").addEventListener("click", handleDeleteCustomer); // Add Contact document.getElementById("btn-add-contact").addEventListener("click", () => { document.getElementById("contact-form").reset(); document.getElementById("contact-id").value = ""; document.getElementById("contact-modal-title").innerText = "담당자 등록"; document.getElementById("contact-modal").style.display = "flex"; }); document.getElementById("contact-form").addEventListener("submit", handleContactSubmit); // Add Activity document.getElementById("btn-add-activity").addEventListener("click", () => { document.getElementById("activity-form").reset(); document.getElementById("activity-id").value = ""; document.getElementById("act-date").value = new Date().toISOString().substring(0, 10); document.getElementById("activity-modal-title").innerText = "활동 일지 등록"; document.getElementById("activity-modal").style.display = "flex"; }); document.getElementById("activity-form").addEventListener("submit", handleActivitySubmit); } // Form Handlers async function handleCustomerSubmit(e) { e.preventDefault(); const id = document.getElementById("customer-id").value; const payload = { name_kr: document.getElementById("cust-name-kr").value, name_en: document.getElementById("cust-name-en").value || null, business_registration_number: document.getElementById("cust-brn").value || null, contact_number: document.getElementById("cust-contact").value || null, address: document.getElementById("cust-address").value || null }; try { let res; if (id) { // Update res = await fetch(`${API_BASE}/${id}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }); } else { // Create res = await fetch(`${API_BASE}/`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }); } if (!res.ok) throw new Error("API error occurred"); const result = await res.json(); document.getElementById("customer-modal").style.display = "none"; await fetchCustomers(); if (id) { showCustomerDetail(parseInt(id)); } else { showCustomerDetail(result.id); } } catch (err) { console.error(err); alert("고객사 정보를 저장하는 중 오류가 발생했습니다."); } } async function handleDeleteCustomer() { if (!selectedCustomerId) return; if (!confirm("이 고객사를 정말 삭제하시겠습니까?\n해당 거래처의 연락처 및 활동 일지 정보가 영구 삭제됩니다.")) return; try { const res = await fetch(`${API_BASE}/${selectedCustomerId}`, { method: "DELETE" }); if (!res.ok) throw new Error("Failed to delete customer"); selectedCustomerId = null; document.getElementById("customer-detail-card").style.display = "none"; document.getElementById("customer-placeholder-card").style.display = "flex"; await fetchCustomers(); } catch (err) { console.error(err); alert("고객사 삭제에 실패했습니다."); } } // Contact Handlers window.openEditContactModal = function(contact) { document.getElementById("contact-id").value = contact.id; document.getElementById("cont-name").value = contact.name; document.getElementById("cont-position").value = contact.position || ""; document.getElementById("cont-phone").value = contact.phone_number || ""; document.getElementById("cont-email").value = contact.email || ""; document.getElementById("cont-location").value = contact.work_location || ""; document.getElementById("contact-modal-title").innerText = "담당자 정보 수정"; document.getElementById("contact-modal").style.display = "flex"; }; async function handleContactSubmit(e) { e.preventDefault(); const id = document.getElementById("contact-id").value; const payload = { customer_id: selectedCustomerId, name: document.getElementById("cont-name").value, position: document.getElementById("cont-position").value || null, phone_number: document.getElementById("cont-phone").value || null, email: document.getElementById("cont-email").value || null, work_location: document.getElementById("cont-location").value || null }; try { let res; if (id) { res = await fetch(`${API_BASE}/contacts/${id}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }); } else { res = await fetch(`${API_BASE}/contacts`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }); } if (!res.ok) throw new Error("Contact save API error"); document.getElementById("contact-modal").style.display = "none"; showCustomerDetail(selectedCustomerId); } catch (err) { console.error(err); alert("담당자 저장에 실패했습니다."); } } window.deleteContact = async function(contactId) { if (!confirm("이 담당자 정보를 정말 삭제하시겠습니까?")) return; try { const res = await fetch(`${API_BASE}/contacts/${contactId}`, { method: "DELETE" }); if (!res.ok) throw new Error("Failed to delete contact"); showCustomerDetail(selectedCustomerId); } catch (err) { console.error(err); alert("담당자 삭제에 실패했습니다."); } }; // Activity Handlers window.openEditActivityModal = function(act) { document.getElementById("activity-id").value = act.id; document.getElementById("act-date").value = act.activity_date; document.getElementById("act-type").value = act.activity_type; document.getElementById("act-memo").value = act.memo || ""; document.getElementById("activity-modal-title").innerText = "활동 일지 수정"; document.getElementById("activity-modal").style.display = "flex"; }; async function handleActivitySubmit(e) { e.preventDefault(); const id = document.getElementById("activity-id").value; const payload = { customer_id: selectedCustomerId, contact_id: null, // Optional in back-end activity_date: document.getElementById("act-date").value, activity_type: document.getElementById("act-type").value, memo: document.getElementById("act-memo").value }; try { let res; if (id) { res = await fetch(`${API_BASE}/activities/${id}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }); } else { res = await fetch(`${API_BASE}/activities`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }); } if (!res.ok) throw new Error("Activity save API error"); document.getElementById("activity-modal").style.display = "none"; showCustomerDetail(selectedCustomerId); } catch (err) { console.error(err); alert("일지 저장에 실패했습니다."); } } window.deleteActivity = async function(actId) { if (!confirm("이 활동 일지를 삭제하시겠습니까?")) return; try { const res = await fetch(`${API_BASE}/activities/${actId}`, { method: "DELETE" }); if (!res.ok) throw new Error("Failed to delete activity"); showCustomerDetail(selectedCustomerId); } catch (err) { console.error(err); alert("일지 삭제에 실패했습니다."); } };