style(project): 새 프로젝트 모달 멤버 선택도 멤버 배정 창과 동일하게 통일

/api/assignable-users 응답에 avatar 필드 추가하고, 아이콘/이름/체크박스
세로 카드(memberPickHtml)를 공용 함수로 뽑아 새 프로젝트 모달(홈·사이드바
둘 다)과 멤버 배정 모달 3곳이 전부 같은 모양을 쓰도록 통일. 홈 페이지는
avatars 맵이 따로 없어서 이 API 응답의 avatar 필드에만 의존하도록 함.
This commit is contained in:
2026-09-16 13:23:40 +09:00
parent 81c8a77f89
commit eb1bae9fc6
5 changed files with 28 additions and 18 deletions
+24 -15
View File
@@ -114,6 +114,21 @@
return mm + "/" + dd + "(" + wd + ")";
}
// 멤버 선택 후보 카드(아이콘 위 / 이름 가운데 / 체크박스 아래) — 새 프로젝트
// 모달(홈·프로젝트 페이지)과 멤버 배정 모달 3곳이 전부 이 함수 하나를 쓴다.
// /api/assignable-users 응답의 avatar 필드를 그대로 쓰므로 페이지별
// avatars 맵(홈 페이지엔 없음)에 기대지 않는다.
function memberPickHtml(u) {
const icon = u.avatar
? '<img class="pj-avatar pj-member-pick-icon" src="' + escapeHtml(u.avatar) + '" alt="" referrerpolicy="no-referrer" />'
: '<span class="material-symbols-outlined pj-gicon pj-member-pick-icon">account_circle</span>';
return '<label class="pj-member-pick pj-member-pick-stacked">' +
'<span class="pj-member-pick-avatar">' + icon + "</span>" +
'<span class="pj-member-pick-name">' + escapeHtml(u.id) + "</span>" +
'<input type="checkbox" value="' + u.email + '" data-name="' + escapeHtml(u.name) + '" />' +
"</label>";
}
// ── 색상 팔레트 렌더 ───────────────────────────────────────
function renderColorPalette(container, onPick, initial) {
const colors = window.PJ_COLORS || ["#4573d2"];
@@ -477,10 +492,9 @@
try {
const res = await api("GET", "/project/api/assignable-users");
const users = res.users || [];
membersBox.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>";
membersBox.innerHTML = users.length
? users.map(memberPickHtml).join("")
: "<span class='pj-empty-sm'>배정 가능한 직원이 없습니다.</span>";
} catch (e) {
membersBox.innerHTML = "<span class='pj-empty-sm'>불러오기 실패</span>";
}
@@ -2503,10 +2517,9 @@
try {
const res = await api("GET", "/project/api/assignable-users");
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>";
newProjMembersBox.innerHTML = users.length
? users.map(memberPickHtml).join("")
: "<span class='pj-empty-sm'>배정 가능한 직원이 없습니다.</span>";
} catch (e) {
newProjMembersBox.innerHTML = "<span class='pj-empty-sm'>불러오기 실패</span>";
}
@@ -2632,13 +2645,9 @@
const res = await api("GET", "/project/api/assignable-users");
const existing = new Set(members.map(function (m) { return m.user_email; }));
const candidates = res.users.filter(function (u) { return !existing.has(u.email); });
box.innerHTML = candidates.length ? candidates.map(function (u) {
return '<label class="pj-member-pick pj-member-pick-stacked">' +
'<span class="pj-member-pick-avatar">' + avatarHtml(u.email, "pj-member-pick-icon") + "</span>" +
'<span class="pj-member-pick-name">' + escapeHtml(u.id) + "</span>" +
'<input type="checkbox" value="' + u.email + '" data-name="' + escapeHtml(u.name) + '" />' +
"</label>";
}).join("") : "<span class='pj-empty-sm'>배정 가능한 직원이 없습니다(권한 미부여 또는 전원 배정됨)</span>";
box.innerHTML = candidates.length
? candidates.map(memberPickHtml).join("")
: "<span class='pj-empty-sm'>배정 가능한 직원이 없습니다(권한 미부여 또는 전원 배정됨)</span>";
} catch (e) {
box.innerHTML = "<span class='pj-empty-sm'>불러오기 실패: " + escapeHtml(e.message) + "</span>";
}