feat: refine seat assignment flow and profile seat preview
This commit is contained in:
@@ -103,6 +103,10 @@ function isAdmin() {
|
||||
return getSession()?.user?.role === "admin";
|
||||
}
|
||||
|
||||
function isSlotBasedSeatMap() {
|
||||
return seatMapState.seatMap?.source_type === "dxf" || seatMapState.seatMap?.source_type === "fixed_html";
|
||||
}
|
||||
|
||||
function escapeHtml(value) {
|
||||
return String(value ?? "")
|
||||
.replaceAll("&", "&")
|
||||
@@ -618,6 +622,24 @@ function getDraftPlacedSlotKeys() {
|
||||
.map((value) => String(value));
|
||||
}
|
||||
|
||||
function getSeatAssignmentPayload() {
|
||||
const slotMap = getSeatSlotMap();
|
||||
const memberMap = getMemberMap();
|
||||
return getPlacementSource()
|
||||
.map((placement) => {
|
||||
const slot = slotMap.get(Number(placement.seat_slot_id));
|
||||
const member = memberMap.get(Number(placement.member_id));
|
||||
if (!slot || !member) return null;
|
||||
return {
|
||||
key: String(slot.slot_key),
|
||||
member_id: Number(member.id),
|
||||
name: member.name || "-",
|
||||
rank: member.rank || "-",
|
||||
};
|
||||
})
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
function syncSeatMapViewerFrame() {
|
||||
const frame = seatMapBoard?.querySelector("#seatmap-dxf-frame");
|
||||
if (!frame?.contentWindow) return;
|
||||
@@ -625,6 +647,22 @@ function syncSeatMapViewerFrame() {
|
||||
{ type: "seatmap-set-placed", keys: getDraftPlacedSlotKeys() },
|
||||
window.location.origin,
|
||||
);
|
||||
frame.contentWindow.postMessage(
|
||||
{ type: "seatmap-set-assignments", items: getSeatAssignmentPayload() },
|
||||
window.location.origin,
|
||||
);
|
||||
}
|
||||
|
||||
function updateSeatMapDraftUi() {
|
||||
if (seatMapSaveBtn) {
|
||||
seatMapSaveBtn.hidden = !isAdmin() || !seatMapState.seatMap;
|
||||
seatMapSaveBtn.disabled = !seatMapState.dirty;
|
||||
}
|
||||
if (seatMapCancelBtn) {
|
||||
seatMapCancelBtn.hidden = !seatMapState.seatMap;
|
||||
}
|
||||
renderUnassignedMembers();
|
||||
syncSeatMapViewerFrame();
|
||||
}
|
||||
|
||||
function setupSeatMapViewerFrame() {
|
||||
@@ -657,7 +695,7 @@ function setupSeatMapViewerFrame() {
|
||||
const matchedSlot = (seatMapState.slots || []).find((item) => String(item.slot_key) === String(picked.key));
|
||||
if (!matchedSlot) return;
|
||||
upsertDraftPlacementForSlot(memberId, Number(matchedSlot.id));
|
||||
renderSeatMap();
|
||||
updateSeatMapDraftUi();
|
||||
});
|
||||
}, { once: true });
|
||||
}
|
||||
@@ -767,6 +805,13 @@ function handleEmbeddedNavigationMessage(event) {
|
||||
hideUserPopover();
|
||||
setActiveView("organization");
|
||||
}
|
||||
if (data.type === "seatmap-clear-slot" && isAdmin()) {
|
||||
const cleared = clearDraftPlacementBySlotKey(String(data.key || ""));
|
||||
if (cleared) {
|
||||
setSeatMapStatus("구성원을 공석으로 이동했습니다. 저장 버튼으로 반영하세요.", "info");
|
||||
updateSeatMapDraftUi();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchJson(url, options) {
|
||||
@@ -848,6 +893,15 @@ async function getImageDimensions(file) {
|
||||
});
|
||||
}
|
||||
|
||||
function clearDraftPlacementBySlotKey(slotKey) {
|
||||
const matchedSlot = (seatMapState.slots || []).find((item) => String(item.slot_key) === String(slotKey));
|
||||
if (!matchedSlot) return false;
|
||||
const placement = (seatMapState.draftPlacements || []).find((item) => Number(item.seat_slot_id) === Number(matchedSlot.id));
|
||||
if (!placement) return false;
|
||||
removeDraftPlacement(Number(placement.member_id));
|
||||
return true;
|
||||
}
|
||||
|
||||
async function uploadSeatMapImage(file, name) {
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
@@ -927,7 +981,7 @@ function handleSeatMapCellDrop(event) {
|
||||
event.preventDefault();
|
||||
const memberId = getDraggedMemberId(event);
|
||||
if (!memberId) return;
|
||||
if (seatMapState.seatMap?.source_type === "dxf") {
|
||||
if (isSlotBasedSeatMap()) {
|
||||
const slot = event.target.closest(".seatmap-slot");
|
||||
if (slot) {
|
||||
upsertDraftPlacementForSlot(memberId, Number(slot.dataset.slotId));
|
||||
@@ -957,7 +1011,7 @@ function handleSeatMapListDrop(event) {
|
||||
const memberId = getDraggedMemberId(event);
|
||||
if (!memberId) return;
|
||||
removeDraftPlacement(memberId);
|
||||
renderSeatMap();
|
||||
updateSeatMapDraftUi();
|
||||
}
|
||||
|
||||
function setActiveView(view) {
|
||||
@@ -1108,7 +1162,7 @@ if (seatMapFormImage) {
|
||||
|
||||
if (seatMapBoard) {
|
||||
seatMapBoard.addEventListener("wheel", (event) => {
|
||||
if (seatMapState.seatMap?.source_type !== "dxf") return;
|
||||
if (!isSlotBasedSeatMap()) return;
|
||||
event.preventDefault();
|
||||
zoomDxfSeatMapAtPoint(event.clientX, event.clientY, event.deltaY < 0 ? 1.08 : 0.92);
|
||||
}, { passive: false });
|
||||
@@ -1119,7 +1173,7 @@ if (seatMapBoard) {
|
||||
});
|
||||
seatMapBoard.addEventListener("dragover", (event) => {
|
||||
if (!seatMapState.editMode) return;
|
||||
const target = seatMapState.seatMap?.source_type === "dxf"
|
||||
const target = isSlotBasedSeatMap()
|
||||
? (event.target.closest(".seatmap-slot") || event.target.closest("#seatmap-dxf-canvas"))
|
||||
: event.target.closest(".seatmap-cell");
|
||||
if (!target) return;
|
||||
@@ -1131,7 +1185,7 @@ if (seatMapBoard) {
|
||||
|
||||
if (seatMapBoardWrap) {
|
||||
seatMapBoardWrap.addEventListener("mousedown", (event) => {
|
||||
if (seatMapState.seatMap?.source_type !== "dxf") return;
|
||||
if (!isSlotBasedSeatMap()) return;
|
||||
if (seatMapBoard?.querySelector("#seatmap-dxf-canvas")) return;
|
||||
if (event.button !== 0) return;
|
||||
if (event.target.closest(".seatmap-member-card, button, input, label")) return;
|
||||
@@ -1150,7 +1204,7 @@ if (seatMapBoardWrap) {
|
||||
updateSeatMapViewerHoverChip();
|
||||
});
|
||||
seatMapBoardWrap.addEventListener("mousemove", (event) => {
|
||||
if (seatMapState.seatMap?.source_type !== "dxf") return;
|
||||
if (!isSlotBasedSeatMap()) return;
|
||||
if (seatMapBoard?.querySelector("#seatmap-dxf-canvas")) return;
|
||||
const slot = event.target.closest(".seatmap-slot");
|
||||
const nextSlotId = slot ? Number(slot.dataset.slotId) : null;
|
||||
@@ -1207,7 +1261,7 @@ setActiveView(currentView);
|
||||
renderAuth();
|
||||
|
||||
window.addEventListener("resize", () => {
|
||||
if (seatMapState.seatMap?.source_type !== "dxf" || currentView !== "seatmap") return;
|
||||
if (!isSlotBasedSeatMap() || currentView !== "seatmap") return;
|
||||
requestAnimationFrame(() => {
|
||||
if (seatMapState.zoom === 1) {
|
||||
centerSeatMapBoard();
|
||||
|
||||
Reference in New Issue
Block a user