fix(project): 프로젝트 목록 + 버튼도 새 프로젝트 팝업으로 열리게 수정
좌측 사이드바 "+ " 버튼이 prompt() 두 번(이름/마감일)으로 대충 만들던 걸 홈 화면과 같은 새 프로젝트 모달(설명·날짜·색상·멤버 선택)로 통일. project.html 에 홈과 동일한 #pj-modal-project 마크업 추가, project.js 는 같은 저장 로직을 쓰되 결과는 mergeProject() 로 사이드바 트리에 patch.
This commit is contained in:
@@ -45,5 +45,5 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/static/project.js?v=20260917e" defer></script>
|
<script src="/static/project.js?v=20260917f" defer></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -393,5 +393,5 @@
|
|||||||
<script>
|
<script>
|
||||||
window.PJ_COLORS = {{ ["#4573d2","#37a3a3","#62a420","#e8a33d","#e8384f","#aa62e3","#f06a6a","#5a6772"] | tojson }};
|
window.PJ_COLORS = {{ ["#4573d2","#37a3a3","#62a420","#e8a33d","#e8384f","#aa62e3","#f06a6a","#5a6772"] | tojson }};
|
||||||
</script>
|
</script>
|
||||||
<script src="/static/project.js?v=20260917e" defer></script>
|
<script src="/static/project.js?v=20260917f" defer></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -223,6 +223,29 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 새 프로젝트 모달 — 좌측 프로젝트 목록의 + 버튼(홈 화면과 동일 폼) -->
|
||||||
|
<div class="pj-modal" id="pj-modal-project" hidden>
|
||||||
|
<div class="pj-modal-card">
|
||||||
|
<h3>새 프로젝트</h3>
|
||||||
|
<label>이름<input type="text" id="pj-f-name" placeholder="프로젝트 이름" /></label>
|
||||||
|
<label>설명<textarea id="pj-f-desc" rows="2"></textarea></label>
|
||||||
|
<div class="pj-form-row">
|
||||||
|
<label>시작일<input type="date" id="pj-f-start" /></label>
|
||||||
|
<label>마감일<input type="date" id="pj-f-due" /></label>
|
||||||
|
</div>
|
||||||
|
<label>색상
|
||||||
|
<span class="pj-color-palette" id="pj-f-colors"></span>
|
||||||
|
</label>
|
||||||
|
<div class="pj-field-label">멤버
|
||||||
|
<div class="pj-member-picker" id="pj-f-members">불러오는 중…</div>
|
||||||
|
</div>
|
||||||
|
<div class="pj-modal-actions">
|
||||||
|
<button type="button" class="pj-btn" data-close>취소</button>
|
||||||
|
<button type="button" class="pj-btn pj-btn-primary" id="pj-save-project">만들기</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 프로젝트 수정 모달 — 좌측 프로젝트 목록의 ✎ 버튼 -->
|
<!-- 프로젝트 수정 모달 — 좌측 프로젝트 목록의 ✎ 버튼 -->
|
||||||
<div class="pj-modal" id="pj-modal-edit" hidden>
|
<div class="pj-modal" id="pj-modal-edit" hidden>
|
||||||
<div class="pj-modal-card">
|
<div class="pj-modal-card">
|
||||||
@@ -438,5 +461,5 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script src="/static/vendor/vis-timeline/vis-timeline-graph2d.min.js"></script>
|
<script src="/static/vendor/vis-timeline/vis-timeline-graph2d.min.js"></script>
|
||||||
<script src="/static/project.js?v=20260917e" defer></script>
|
<script src="/static/project.js?v=20260917f" defer></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
+49
-6
@@ -2487,16 +2487,59 @@
|
|||||||
|
|
||||||
// 새 최상위 프로젝트 (관리자)
|
// 새 최상위 프로젝트 (관리자)
|
||||||
const newProjSide = el("pj-new-project-side");
|
const newProjSide = el("pj-new-project-side");
|
||||||
if (newProjSide) newProjSide.addEventListener("click", async function () {
|
const newProjModal = el("pj-modal-project");
|
||||||
const name = prompt("새 프로젝트 이름");
|
if (newProjSide && newProjModal) {
|
||||||
if (!name || !name.trim()) return;
|
wireModalClose(newProjModal);
|
||||||
const due = prompt("마감일 (YYYY-MM-DD, 없으면 취소 없이 비워두고 확인)") || "";
|
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 = "<span class='pj-empty-sm'>멤버 배정은 관리자가 나중에 할 수 있습니다.</span>";
|
||||||
|
} else {
|
||||||
|
newProjMembersBox.innerHTML = "불러오는 중…";
|
||||||
try {
|
try {
|
||||||
const res = await api("POST", "/project/api/projects", { name: name.trim(), due_date: due.trim() || null });
|
const res = await api("GET", "/project/api/assignable-users");
|
||||||
stagesByProject[res.project.id] = [];
|
const users = res.users || [];
|
||||||
|
newProjMembersBox.innerHTML = users.length ? users.map(function (u) {
|
||||||
|
return '<label class="pj-member-pick"><input type="checkbox" value="' + u.email + '" /> ' +
|
||||||
|
escapeHtml(u.id) + "</label>";
|
||||||
|
}).join("") : "<span class='pj-empty-sm'>배정 가능한 직원이 없습니다.</span>";
|
||||||
|
} catch (e) {
|
||||||
|
newProjMembersBox.innerHTML = "<span class='pj-empty-sm'>불러오기 실패</span>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
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);
|
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"); }
|
} catch (e) { showToast("생성 실패: " + e.message, "error"); }
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// ── 좌측 프로젝트 목록 ✎ 버튼 — 프로젝트 수정 모달(홈 화면과 동일).
|
// ── 좌측 프로젝트 목록 ✎ 버튼 — 프로젝트 수정 모달(홈 화면과 동일).
|
||||||
// 트리는 renderTree() 로 매번 다시 그려지므로(라이브 새로고침 포함) 열기
|
// 트리는 renderTree() 로 매번 다시 그려지므로(라이브 새로고침 포함) 열기
|
||||||
|
|||||||
Reference in New Issue
Block a user