feat: feedback edit/delete buttons and author name on edit
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -44,7 +44,7 @@ router.post('/:taskId', async (req, res, next) => {
|
||||
// PATCH /api/details/item/:id
|
||||
router.patch('/item/:id', async (req, res, next) => {
|
||||
try {
|
||||
const { content } = req.body as Record<string, string>;
|
||||
const { content, authorName } = req.body as Record<string, string>;
|
||||
if (!content?.toString().trim()) throw new AppError(400, '피드백 내용은 필수입니다.');
|
||||
|
||||
const existing = await prisma.taskDetail.findUnique({ where: { id: req.params.id } });
|
||||
@@ -52,7 +52,10 @@ router.patch('/item/:id', async (req, res, next) => {
|
||||
|
||||
const detail = await prisma.taskDetail.update({
|
||||
where: { id: req.params.id },
|
||||
data: { content: content.toString().trim() },
|
||||
data: {
|
||||
content: content.toString().trim(),
|
||||
...(authorName !== undefined && { authorName: authorName?.toString().trim() || null }),
|
||||
},
|
||||
include: { author: { select: { id: true, name: true } } },
|
||||
});
|
||||
|
||||
|
||||
@@ -66,18 +66,18 @@ export function FeedbackModal({
|
||||
/>
|
||||
</label>
|
||||
|
||||
{mode === 'add' && (
|
||||
<label className="block">
|
||||
<span className="mb-1 block text-sm font-bold text-slate-500">이름 *</span>
|
||||
<input
|
||||
required
|
||||
value={form.authorName}
|
||||
onChange={(e) => setForm((p) => ({ ...p, authorName: e.target.value }))}
|
||||
className="w-full rounded-lg border border-slate-200 px-3 py-2 text-base focus:border-emerald-400 focus:outline-none"
|
||||
placeholder="작성자 이름"
|
||||
/>
|
||||
</label>
|
||||
)}
|
||||
<label className="block">
|
||||
<span className="mb-1 block text-sm font-bold text-slate-500">
|
||||
이름 {mode === 'add' ? '*' : ''}
|
||||
</span>
|
||||
<input
|
||||
required={mode === 'add'}
|
||||
value={form.authorName}
|
||||
onChange={(e) => setForm((p) => ({ ...p, authorName: e.target.value }))}
|
||||
className="w-full rounded-lg border border-slate-200 px-3 py-2 text-base focus:border-emerald-400 focus:outline-none"
|
||||
placeholder="작성자 이름"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end gap-2 border-t border-slate-100 px-6 py-4">
|
||||
|
||||
@@ -373,6 +373,7 @@ function DetailView({ task }: { task: TaskWithRelations }) {
|
||||
} else if (feedbackModal?.detail) {
|
||||
await apiClient.patch(`/details/item/${feedbackModal.detail.id}`, {
|
||||
content: data.content.trim(),
|
||||
authorName: data.authorName.trim() || null,
|
||||
});
|
||||
}
|
||||
await qc.invalidateQueries({ queryKey: ['task', task.id] });
|
||||
@@ -516,23 +517,45 @@ function DetailView({ task }: { task: TaskWithRelations }) {
|
||||
}}
|
||||
>
|
||||
{sortedFeedbacks.length === 0 ? (
|
||||
<p className="text-lg text-slate-400">우클릭 또는 + 버튼으로 피드백을 추가하세요.</p>
|
||||
<p className="text-lg text-slate-400">+ 버튼 또는 빈 곳 우클릭으로 피드백을 추가하세요.</p>
|
||||
) : (
|
||||
<div className="mb-2 min-h-0 flex-1 space-y-2">
|
||||
{sortedFeedbacks.map((f) => (
|
||||
<div
|
||||
key={f.id}
|
||||
className="rounded-lg bg-slate-50 px-3 py-2"
|
||||
className="flex items-start justify-between gap-2 rounded-lg bg-slate-50 px-3 py-2"
|
||||
onContextMenu={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setFeedbackCtx({ x: e.clientX, y: e.clientY, detailId: f.id });
|
||||
}}
|
||||
>
|
||||
<p className="truncate text-2xl font-black leading-snug text-slate-700">
|
||||
<p className="min-w-0 flex-1 truncate text-2xl font-black leading-snug text-slate-700">
|
||||
{f.content}
|
||||
<span className="font-bold text-slate-400"> — {feedbackAuthorName(f)}</span>
|
||||
</p>
|
||||
<div className="flex shrink-0 items-center gap-1 pt-0.5">
|
||||
<button
|
||||
type="button"
|
||||
title="피드백 수정"
|
||||
onClick={() => setFeedbackModal({ mode: 'edit', detail: f })}
|
||||
className="rounded px-2 py-0.5 text-xs font-bold text-slate-500 hover:bg-slate-100"
|
||||
>
|
||||
✏️
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
title="피드백 삭제"
|
||||
onClick={() => {
|
||||
if (window.confirm('이 피드백을 삭제하시겠습니까?')) {
|
||||
deleteFeedback.mutate(f.id);
|
||||
}
|
||||
}}
|
||||
className="rounded px-2 py-0.5 text-xs font-bold text-red-400 hover:bg-red-50 hover:text-red-600"
|
||||
>
|
||||
🗑
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user