This commit is contained in:
1 parent
a332ed0d8e
commit
efd1bf2e3c
6 files changed
+122
-24
No files matched your search
+66
-17
@@ -45,6 +45,11 @@
|
||||
return "";
|
||||
}
|
||||
|
||||
function toBoolean(value) {
|
||||
if (value === true || value === 1) return true;
|
||||
return ["true", "1", "yes", "y"].indexOf(String(value || "").trim().toLowerCase()) > -1;
|
||||
}
|
||||
|
||||
function normalizeCategory(value) {
|
||||
const raw = String(value || "").trim();
|
||||
return ({
|
||||
@@ -60,13 +65,17 @@
|
||||
function normalizeRemotePost(item) {
|
||||
item = item || {};
|
||||
const requester = item.requester || item.author || item.user || {};
|
||||
const fields = item.fields && typeof item.fields === "object" && !Array.isArray(item.fields) ? item.fields : {};
|
||||
const fields = [item.fields, item.metadata, item.meta, item.extra_fields, item.data].find(function (candidate) { return candidate && typeof candidate === "object" && !Array.isArray(candidate); }) || {};
|
||||
function value(keys) {
|
||||
return firstValue(item, keys) || firstValue(fields, keys) || firstValue(requester, keys);
|
||||
}
|
||||
const createdAt = value(["createdAt", "created_at", "date"]) || new Date().toISOString();
|
||||
const secret = value(["is_secret", "isSecret", "secret"]);
|
||||
const requesterEmail = value(["requester_email", "requesterEmail", "email"]);
|
||||
const completionRequested = value(["completion_requested", "completionRequested"]);
|
||||
const completionConfirmed = value(["completion_confirmed", "completionConfirmed"]);
|
||||
const completionRequestedAt = value(["completion_requested_at", "completionRequestedAt"]);
|
||||
const completionConfirmedAt = value(["completion_confirmed_at", "completionConfirmedAt"]);
|
||||
return {
|
||||
id: value(["id", "feedbackId", "feedback_id"]),
|
||||
feedbackId: value(["id", "feedbackId", "feedback_id"]),
|
||||
@@ -82,7 +91,11 @@
|
||||
date: String(createdAt).slice(0, 10),
|
||||
createdAt: createdAt,
|
||||
status: normalizeStatus(value(["feedback_status", "feedbackStatus", "status_code", "status"])),
|
||||
secret: secret === true || String(secret).toLowerCase() === "true" || String(secret) === "1",
|
||||
secret: toBoolean(secret),
|
||||
completionRequested: toBoolean(completionRequested) || Boolean(completionRequestedAt),
|
||||
completionRequestedAt: completionRequestedAt,
|
||||
completionConfirmed: toBoolean(completionConfirmed) || Boolean(completionConfirmedAt),
|
||||
completionConfirmedAt: completionConfirmedAt,
|
||||
attachments: value(["attachments", "images"]) || [],
|
||||
raw: item
|
||||
};
|
||||
@@ -356,7 +369,7 @@
|
||||
|
||||
async function requestJson(path, options) {
|
||||
const requestPath = String(path).split("?")[0];
|
||||
const sameOriginProxy = !config.apiBaseUrl && (requestPath === config.createFeedbackPath || requestPath === "/api/feedbacks" || /^\/api\/feedbacks\/[^\/]+(?:\/comments)?$/.test(requestPath));
|
||||
const sameOriginProxy = !config.apiBaseUrl && (requestPath === config.createFeedbackPath || requestPath === "/api/feedbacks" || /^\/api\/feedbacks\/[^\/]+(?:\/comments|\/completion-confirmation)?$/.test(requestPath));
|
||||
if (!config.apiBaseUrl && !sameOriginProxy) return { local: true };
|
||||
const target = config.apiBaseUrl ? config.apiBaseUrl.replace(/\/$/, '') + path : path;
|
||||
const response = await fetch(target, Object.assign({ credentials: 'include' }, options));
|
||||
@@ -529,15 +542,15 @@
|
||||
if (detailListLink) detailListLink.textContent = '목록으로';
|
||||
const bottomBackButton = qs('#backButton', detail);
|
||||
if (bottomBackButton && bottomBackButton.parentElement) bottomBackButton.parentElement.remove();
|
||||
const id = new URLSearchParams(window.location.search).get('id') || 'EG-1048';
|
||||
let post = getPosts().find(function (item) { return item.id === id; });
|
||||
if (!post) {
|
||||
try {
|
||||
const result = await requestJson("/api/feedbacks/" + encodeURIComponent(id), { method: "GET" });
|
||||
post = normalizeRemotePost(result.feedback || result.data || result);
|
||||
} catch (error) {
|
||||
console.warn("[QA] feedback detail load failed:", error.message);
|
||||
}
|
||||
const id = new URLSearchParams(window.location.search).get("id") || "EG-1048";
|
||||
const storedPost = getPosts().find(function (item) { return item.id === id; });
|
||||
let post = storedPost;
|
||||
try {
|
||||
const result = await requestJson("/api/feedbacks/" + encodeURIComponent(id), { method: "GET" });
|
||||
const remotePost = normalizeRemotePost(result.feedback || result.data || result);
|
||||
if (remotePost.id) post = Object.assign({}, storedPost || {}, remotePost);
|
||||
} catch (error) {
|
||||
console.warn("[QA] feedback detail load failed:", error.message);
|
||||
}
|
||||
if (!post) {
|
||||
qs('[data-detail-title]').textContent = '문의 내용을 찾을 수 없습니다.';
|
||||
@@ -546,10 +559,18 @@
|
||||
}
|
||||
qs('[data-detail-category]').textContent = post.category;
|
||||
qs('[data-detail-title]').textContent = post.title;
|
||||
qs('[data-detail-status]').textContent = normalizeStatus(post.status) || '공지';
|
||||
const renderDetailStatus = function () {
|
||||
const statusElement = qs("[data-detail-status]");
|
||||
const status = normalizeStatus(post.status) || "공지";
|
||||
if (!statusElement) return;
|
||||
statusElement.textContent = status;
|
||||
statusElement.classList.toggle("done", status === "완료");
|
||||
statusElement.classList.toggle("review", status !== "완료");
|
||||
};
|
||||
renderDetailStatus();
|
||||
qs('[data-detail-date]').textContent = post.date;
|
||||
qs('[data-detail-author]').textContent = post.author;
|
||||
const detailUser = getAuthUser();
|
||||
let detailUser = getAuthUser();
|
||||
qs('[data-detail-company]').textContent = getPostCompanyLabel(post, detailUser);
|
||||
qs('[data-detail-department]').textContent = post.department;
|
||||
qs('[data-detail-content]').textContent = post.content;
|
||||
@@ -563,13 +584,41 @@
|
||||
const deleteButton = qs('#deleteButton');
|
||||
const editForm = qs('#editForm');
|
||||
const editError = qs('#editError');
|
||||
const completionNotice = qs("#completionNotice");
|
||||
const completionButton = qs("#completionButton");
|
||||
const renderCompletionNotice = function () {
|
||||
const owner = isPostOwner(post, detailUser || getAuthUser());
|
||||
const visible = owner && post.completionRequested && !post.completionConfirmed;
|
||||
if (completionNotice) completionNotice.hidden = !visible;
|
||||
};
|
||||
const ownerActions = function () {
|
||||
const owner = isPostOwner(post, getAuthUser());
|
||||
const owner = isPostOwner(post, detailUser || getAuthUser());
|
||||
if (editButton) editButton.hidden = !owner;
|
||||
if (deleteButton) deleteButton.hidden = !owner;
|
||||
renderCompletionNotice();
|
||||
};
|
||||
ownerActions();
|
||||
if (authReady) authReady.then(ownerActions);
|
||||
if (authReady) authReady.then(function (user) { detailUser = user || detailUser; ownerActions(); renderCompletionNotice(); });
|
||||
if (completionButton) completionButton.addEventListener("click", async function () {
|
||||
if (!post.completionRequested || post.completionConfirmed) return;
|
||||
completionButton.disabled = true;
|
||||
completionButton.textContent = "확인 처리 중...";
|
||||
try {
|
||||
await requestJson("/api/feedbacks/" + encodeURIComponent(post.id) + "/completion-confirmation", { method: "POST" });
|
||||
post.completionRequested = false;
|
||||
post.completionConfirmed = true;
|
||||
post.status = "완료";
|
||||
updateStoredPost(post);
|
||||
renderDetailStatus();
|
||||
renderCompletionNotice();
|
||||
showToast("문의가 완료 처리되었습니다.");
|
||||
} catch (error) {
|
||||
showToast(error.message || "문의 완료 확인에 실패했습니다.");
|
||||
} finally {
|
||||
completionButton.disabled = false;
|
||||
completionButton.textContent = "완료 확인";
|
||||
}
|
||||
});
|
||||
if (editButton && editForm) editButton.addEventListener('click', function () {
|
||||
qs('#editCategory').value = post.category || '일반문의';
|
||||
qs('#editTitle').value = post.title || '';
|
||||
@@ -741,7 +790,7 @@
|
||||
}).join('');
|
||||
});
|
||||
refreshRemoteStatus(post).then(function (changed) {
|
||||
if (changed) qs('[data-detail-status]').textContent = normalizeStatus(post.status) || '공지';
|
||||
if (changed) renderDetailStatus();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user