This commit is contained in:
1 parent
710229879e
commit
e4843e7d1d
3 files changed
+124
-3
No files matched your search
+64
-3
@@ -417,7 +417,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|\/completion-confirmation)?$/.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));
|
||||
@@ -651,7 +651,7 @@
|
||||
renderCompletionNotice();
|
||||
};
|
||||
ownerActions();
|
||||
if (authReady) authReady.then(function (user) { detailUser = user || detailUser; ownerActions(); renderCompletionNotice(); });
|
||||
if (authReady) authReady.then(function (user) { detailUser = user || detailUser; ownerActions(); renderCompletionNotice(); comments = renderComments(comments); });
|
||||
if (completionButton) completionButton.addEventListener("click", async function () {
|
||||
if (!post.completionRequested || post.completionConfirmed) return;
|
||||
completionButton.disabled = true;
|
||||
@@ -762,6 +762,7 @@
|
||||
const rawAttachments = comment.attachments || comment.images || comment.comment_attachments || comment.commentAttachments || [];
|
||||
return {
|
||||
id: comment.id || '',
|
||||
authorId: comment.author_id || comment.authorId || comment.requester_id || comment.requesterId || '',
|
||||
author: comment.author_name || comment.authorName || comment.author?.name || comment.author || '작성자',
|
||||
date: formatKoreanDateTime(comment.created_at || comment.createdAt || comment.updated_at || '', true),
|
||||
content: comment.content || comment.body || '',
|
||||
@@ -778,10 +779,27 @@
|
||||
}).join('');
|
||||
}
|
||||
|
||||
let editingCommentId = '';
|
||||
function isCommentOwner(comment, user) {
|
||||
const authorId = String(comment.authorId || '').trim().toLowerCase();
|
||||
const userIds = [user && user.requesterId, user && user.ssoSubject, user && user.userUuid].map(function (id) { return String(id || '').trim().toLowerCase(); }).filter(Boolean);
|
||||
return Boolean(authorId && userIds.indexOf(authorId) !== -1);
|
||||
}
|
||||
|
||||
function renderComments(comments) {
|
||||
comments = (comments || []).map(normalizeComment).filter(function (comment) { return comment.content; });
|
||||
qs('#commentCount').textContent = comments.length;
|
||||
qs('#comments').innerHTML = comments.length ? comments.map(function (comment) { return '<div class="comment"><div class="comment-meta"><strong>' + escapeHtml(comment.author) + '</strong><span>' + escapeHtml(comment.date) + '</span></div><div class="comment-content">' + escapeHtml(comment.content) + '</div>' + (comment.attachments.length ? '<div class="comment-attachments-list">' + renderCommentAttachments(comment.attachments) + '</div>' : '') + '</div>'; }).join('') : '<div class="comment-empty">등록된 답변이 없습니다.</div>';
|
||||
const user = detailUser || getAuthUser();
|
||||
qs('#comments').innerHTML = comments.length ? comments.map(function (comment) {
|
||||
const owner = isCommentOwner(comment, user);
|
||||
const editing = editingCommentId === comment.id && owner;
|
||||
const actions = owner ? '<div class="comment-actions"><button class="button button-outline" type="button" data-comment-edit="' + escapeHtml(comment.id) + '">수정</button><button class="button button-danger" type="button" data-comment-delete="' + escapeHtml(comment.id) + '">삭제</button></div>' : '';
|
||||
const content = editing ? '<textarea class="textarea comment-edit-input" data-comment-edit-input maxlength="5000">' + escapeHtml(comment.content) + '</textarea><div class="comment-actions"><button class="button button-outline" type="button" data-comment-cancel>취소</button><button class="button button-primary" type="button" data-comment-save="' + escapeHtml(comment.id) + '">저장</button></div>' : '<div class="comment-content">' + escapeHtml(comment.content) + '</div>';
|
||||
return '<div class="comment" data-comment-id="' + escapeHtml(comment.id) + '"><div class="comment-meta"><strong>' + escapeHtml(comment.author) + '</strong><span>' + escapeHtml(comment.date) + '</span></div>' + content + (comment.attachments.length ? '<div class="comment-attachments-list">' + renderCommentAttachments(comment.attachments) + '</div>' : '') + (editing ? '' : actions) + '</div>';
|
||||
}).join('') : '<div class="comment-empty">등록된 답변이 없습니다.</div>';
|
||||
const storedComments = getComments();
|
||||
storedComments[post.id] = comments;
|
||||
localStorage.setItem(COMMENTS_KEY, JSON.stringify(storedComments));
|
||||
return comments;
|
||||
}
|
||||
let comments = renderComments(getComments()[post.id] || []);
|
||||
@@ -791,6 +809,48 @@
|
||||
}).catch(function (error) {
|
||||
console.warn('[QA] comments load failed:', error.message);
|
||||
});
|
||||
qs('#comments').addEventListener('click', async function (event) {
|
||||
const editButton = event.target.closest('[data-comment-edit]');
|
||||
const cancelButton = event.target.closest('[data-comment-cancel]');
|
||||
const saveButton = event.target.closest('[data-comment-save]');
|
||||
const deleteButton = event.target.closest('[data-comment-delete]');
|
||||
if (editButton) {
|
||||
editingCommentId = editButton.getAttribute('data-comment-edit');
|
||||
comments = renderComments(comments);
|
||||
const input = qs('[data-comment-edit-input]');
|
||||
if (input) { input.focus(); input.setSelectionRange(input.value.length, input.value.length); }
|
||||
return;
|
||||
}
|
||||
if (cancelButton) { editingCommentId = ''; comments = renderComments(comments); return; }
|
||||
if (saveButton) {
|
||||
const commentId = saveButton.getAttribute('data-comment-save');
|
||||
const comment = comments.find(function (item) { return item.id === commentId; });
|
||||
const input = qs('[data-comment-edit-input]');
|
||||
const content = input ? input.value.trim() : '';
|
||||
if (!content) { showToast('댓글 내용을 입력해주세요.'); return; }
|
||||
saveButton.disabled = true;
|
||||
try {
|
||||
const result = await requestJson(commentsPath + '/' + encodeURIComponent(commentId), { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ content: content }) });
|
||||
const updatedComment = normalizeComment(Object.assign({}, comment, result.comment || result, { content: content }));
|
||||
comments = comments.map(function (item) { return item.id === commentId ? updatedComment : item; });
|
||||
editingCommentId = '';
|
||||
renderComments(comments);
|
||||
showToast('댓글이 수정되었습니다.');
|
||||
} catch (error) { showToast(error.message || '댓글 수정에 실패했습니다.'); saveButton.disabled = false; }
|
||||
return;
|
||||
}
|
||||
if (deleteButton) {
|
||||
const commentId = deleteButton.getAttribute('data-comment-delete');
|
||||
if (!window.confirm('이 댓글을 삭제하시겠습니까?')) return;
|
||||
deleteButton.disabled = true;
|
||||
try {
|
||||
await requestJson(commentsPath + '/' + encodeURIComponent(commentId), { method: 'DELETE' });
|
||||
comments = comments.filter(function (item) { return item.id !== commentId; });
|
||||
renderComments(comments);
|
||||
showToast('댓글이 삭제되었습니다.');
|
||||
} catch (error) { showToast(error.message || '댓글 삭제에 실패했습니다.'); deleteButton.disabled = false; }
|
||||
}
|
||||
});
|
||||
const commentForm = qs('#commentForm');
|
||||
if (commentForm) commentForm.addEventListener('submit', async function (event) {
|
||||
event.preventDefault();
|
||||
@@ -816,6 +876,7 @@
|
||||
const result = await postToApi(commentsPath, payload);
|
||||
const localAttachments = files.map(function (file) { const url = URL.createObjectURL(file); return { name: file.name, url: url, thumbnailUrl: url }; });
|
||||
const savedComment = normalizeComment(result.comment || { id: result.id, content: content, author: (getAuthUser() || {}).name || '작성자', createdAt: new Date().toISOString(), attachments: localAttachments });
|
||||
if (!savedComment.authorId) savedComment.authorId = (getAuthUser() || {}).requesterId || '';
|
||||
if (!savedComment.attachments.length) savedComment.attachments = localAttachments;
|
||||
comments.push(savedComment);
|
||||
renderComments(comments);
|
||||
|
||||
Reference in new issue
Block a user