diff --git a/app/modules/project/templates/project/inbox.html b/app/modules/project/templates/project/inbox.html
index b78024d..33f37e1 100644
--- a/app/modules/project/templates/project/inbox.html
+++ b/app/modules/project/templates/project/inbox.html
@@ -45,5 +45,5 @@
{% endif %}
-
+
{% endblock %}
diff --git a/app/modules/project/templates/project/index.html b/app/modules/project/templates/project/index.html
index 83d0567..dfba77e 100644
--- a/app/modules/project/templates/project/index.html
+++ b/app/modules/project/templates/project/index.html
@@ -393,5 +393,5 @@
-
+
{% endblock %}
diff --git a/app/modules/project/templates/project/project.html b/app/modules/project/templates/project/project.html
index d7060ec..0d1eadc 100644
--- a/app/modules/project/templates/project/project.html
+++ b/app/modules/project/templates/project/project.html
@@ -223,6 +223,29 @@
+
+
@@ -438,5 +461,5 @@
-
+
{% endblock %}
diff --git a/app/static/project.js b/app/static/project.js
index f86013b..b5a940d 100644
--- a/app/static/project.js
+++ b/app/static/project.js
@@ -2487,16 +2487,59 @@
// 새 최상위 프로젝트 (관리자)
const newProjSide = el("pj-new-project-side");
- if (newProjSide) newProjSide.addEventListener("click", async function () {
- const name = prompt("새 프로젝트 이름");
- if (!name || !name.trim()) return;
- const due = prompt("마감일 (YYYY-MM-DD, 없으면 취소 없이 비워두고 확인)") || "";
- try {
- const res = await api("POST", "/project/api/projects", { name: name.trim(), due_date: due.trim() || null });
- stagesByProject[res.project.id] = [];
- mergeProject(res.project);
- } catch (e) { showToast("생성 실패: " + e.message, "error"); }
- });
+ const newProjModal = el("pj-modal-project");
+ if (newProjSide && newProjModal) {
+ wireModalClose(newProjModal);
+ const getNewProjColor = renderColorPalette(el("pj-f-colors"));
+ const newProjMembersBox = el("pj-f-members");
+ newProjSide.addEventListener("click", async function () {
+ openModal(newProjModal);
+ if (newProjMembersBox) {
+ // 멤버 배정은 관리자 전용 API — 관리자가 아니면 시도하지 않고 안내만.
+ if (!isAdmin) {
+ newProjMembersBox.innerHTML = "멤버 배정은 관리자가 나중에 할 수 있습니다.";
+ } else {
+ newProjMembersBox.innerHTML = "불러오는 중…";
+ try {
+ const res = await api("GET", "/project/api/assignable-users");
+ const users = res.users || [];
+ newProjMembersBox.innerHTML = users.length ? users.map(function (u) {
+ return '";
+ }).join("") : "배정 가능한 직원이 없습니다.";
+ } catch (e) {
+ newProjMembersBox.innerHTML = "불러오기 실패";
+ }
+ }
+ }
+ });
+ el("pj-save-project").addEventListener("click", async function () {
+ const name = el("pj-f-name").value.trim();
+ if (!name) { alert("이름을 입력하세요."); return; }
+ const memberEmails = newProjMembersBox
+ ? Array.from(newProjMembersBox.querySelectorAll("input[type=checkbox]:checked")).map(function (c) { return c.value; })
+ : [];
+ try {
+ const res = await api("POST", "/project/api/projects", {
+ name: name,
+ description: el("pj-f-desc").value.trim(),
+ start_date: el("pj-f-start").value || null,
+ due_date: el("pj-f-due").value || null,
+ color: getNewProjColor(),
+ });
+ const pid = res.project.id;
+ for (const email of memberEmails) {
+ try { await api("POST", "/project/api/projects/" + pid + "/members", { user_email: email }); }
+ catch (_) {}
+ }
+ stagesByProject[pid] = [];
+ mergeProject(res.project);
+ closeModal(newProjModal);
+ el("pj-f-name").value = ""; el("pj-f-desc").value = "";
+ el("pj-f-start").value = ""; el("pj-f-due").value = "";
+ } catch (e) { showToast("생성 실패: " + e.message, "error"); }
+ });
+ }
// ── 좌측 프로젝트 목록 ✎ 버튼 — 프로젝트 수정 모달(홈 화면과 동일).
// 트리는 renderTree() 로 매번 다시 그려지므로(라이브 새로고침 포함) 열기