feat: mazanie pripomienok v editore aj na stranke s odkazom

- editor: tlacidlo Zmazat v bubline pripomienky na platne
- odkaz: Zmazat v bubline aj ikona kosa v zozname pripomienok
- pred zmazanim potvrdenie (zmizne pre vsetkych s odkazom)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jakub_HostacnyandClaude Opus 5.5 committed 2026-10-21 11:44:59 +02:00
1 parent cfacf2474b
commit 061e647180
2 files changed
+60 -7

No files matched your search

+14
View File
@@ -928,6 +928,7 @@ export default function Home() {
selectedId={selectedCommentId} selectedId={selectedCommentId}
onSelect={setSelectedCommentId} onSelect={setSelectedCommentId}
renderActions={(c: ReviewComment) => ( renderActions={(c: ReviewComment) => (
<>
<button <button
type="button" type="button"
onClick={() => reviews.toggleDone(c)} onClick={() => reviews.toggleDone(c)}
@@ -937,6 +938,19 @@ export default function Home() {
> >
{c.done ? 'Vrátiť ako neurobené' : '✓ Označiť ako hotové'} {c.done ? 'Vrátiť ako neurobené' : '✓ Označiť ako hotové'}
</button> </button>
<button
type="button"
onClick={() => {
if (confirm('Zmazať túto pripomienku? Zmizne aj pre ostatných s odkazom.')) {
reviews.remove(c);
setSelectedCommentId(null);
}
}}
className="text-[11px] font-bold px-2.5 py-1 rounded-lg text-red-700 bg-red-50 hover:bg-red-100"
>
Zmazať
</button>
</>
)} )}
/> />
)} )}
+46 -7
View File
@@ -3,7 +3,7 @@
// Náhľad newslettra na pripomienky (zdieľaný odkaz). Nič sa tu nedá upravovať – len komentovať, // Náhľad newslettra na pripomienky (zdieľaný odkaz). Nič sa tu nedá upravovať – len komentovať,
// písať text priamo do newslettra a kresliť. Pripomienky sa ukladajú k odkazu, vidí ich každý s odkazom. // písať text priamo do newslettra a kresliť. Pripomienky sa ukladajú k odkazu, vidí ich každý s odkazom.
import React, { use, useCallback, useEffect, useRef, useState } from 'react'; import React, { use, useCallback, useEffect, useRef, useState } from 'react';
import { MessageCircle, Type, Pencil, MousePointer2, CheckCircle2, Loader2 } from 'lucide-react'; import { MessageCircle, Type, Pencil, MousePointer2, CheckCircle2, Loader2, Trash2 } from 'lucide-react';
import { renderSingleModuleHtml } from '@/lib/emailRenderer'; import { renderSingleModuleHtml } from '@/lib/emailRenderer';
import { import {
Review, Review,
@@ -12,7 +12,8 @@ import {
REVIEW_COLORS, REVIEW_COLORS,
getReviewByToken, getReviewByToken,
listReviewComments, listReviewComments,
addReviewComment addReviewComment,
deleteReviewComment
} from '@/lib/reviews'; } from '@/lib/reviews';
import { AnnotationLayer, pointToModuleCoords, useModuleLayout } from '@/components/review/AnnotationLayer'; import { AnnotationLayer, pointToModuleCoords, useModuleLayout } from '@/components/review/AnnotationLayer';
import { NewsletterCampaign } from '@/types/newsletter'; import { NewsletterCampaign } from '@/types/newsletter';
@@ -124,6 +125,18 @@ export default function ReviewPage({ params }: { params: Promise<{ token: string
} }
}; };
// Zmazanie pripomienky (zmizne pre všetkých s odkazom aj v editore)
const removeComment = async (c: ReviewComment) => {
if (!confirm('Zmazať túto pripomienku? Zmizne aj pre ostatných s odkazom.')) return;
try {
await deleteReviewComment(c.id);
setComments((prev) => prev.filter((x) => x.id !== c.id));
if (selectedId === c.id) setSelectedId(null);
} catch (e) {
alert(e instanceof Error ? e.message : 'Pripomienku sa nepodarilo zmazať.');
}
};
// Klik do newslettra: komentár / text → okienko na napísanie // Klik do newslettra: komentár / text → okienko na napísanie
const onCanvasClick = (e: React.MouseEvent) => { const onCanvasClick = (e: React.MouseEvent) => {
if (tool !== 'comment' && tool !== 'text') return; if (tool !== 'comment' && tool !== 'text') return;
@@ -246,7 +259,21 @@ export default function ReviewPage({ params }: { params: Promise<{ token: string
/> />
))} ))}
<AnnotationLayer layout={layout} comments={comments} selectedId={selectedId} onSelect={setSelectedId} /> <AnnotationLayer
layout={layout}
comments={comments}
selectedId={selectedId}
onSelect={setSelectedId}
renderActions={(c) => (
<button
type="button"
onClick={() => removeComment(c)}
className="flex items-center gap-1 text-[11px] font-bold px-2.5 py-1 rounded-lg text-red-700 bg-red-50 hover:bg-red-100"
>
<Trash2 className="w-3 h-3" /> Zmazať
</button>
)}
/>
{/* Plocha na pridávanie pripomienok */} {/* Plocha na pridávanie pripomienok */}
{tool !== 'view' && ( {tool !== 'view' && (
@@ -338,11 +365,12 @@ export default function ReviewPage({ params }: { params: Promise<{ token: string
{comments.map((c) => { {comments.map((c) => {
const number = comments.filter((x) => x.kind === 'comment').indexOf(c) + 1; const number = comments.filter((x) => x.kind === 'comment').indexOf(c) + 1;
return ( return (
<button <div
key={c.id} key={c.id}
type="button" role="button"
tabIndex={0}
onClick={() => setSelectedId(c.id === selectedId ? null : c.id)} onClick={() => setSelectedId(c.id === selectedId ? null : c.id)}
className={`w-full text-left rounded-lg border p-2 transition-colors ${ className={`group w-full text-left rounded-lg border p-2 transition-colors cursor-pointer ${
c.id === selectedId ? 'border-gray-900 bg-gray-50' : 'border-gray-200 hover:border-gray-300' c.id === selectedId ? 'border-gray-900 bg-gray-50' : 'border-gray-200 hover:border-gray-300'
} ${c.done ? 'opacity-60' : ''}`} } ${c.done ? 'opacity-60' : ''}`}
> >
@@ -353,11 +381,22 @@ export default function ReviewPage({ params }: { params: Promise<{ token: string
<span className="text-[11px] font-bold text-gray-900 truncate">{c.author || 'Anonym'}</span> <span className="text-[11px] font-bold text-gray-900 truncate">{c.author || 'Anonym'}</span>
{c.done && <CheckCircle2 className="w-3.5 h-3.5 text-emerald-600 shrink-0" />} {c.done && <CheckCircle2 className="w-3.5 h-3.5 text-emerald-600 shrink-0" />}
<span className="ml-auto text-[10px] text-gray-400 shrink-0">{new Date(c.created_at).toLocaleDateString('sk-SK')}</span> <span className="ml-auto text-[10px] text-gray-400 shrink-0">{new Date(c.created_at).toLocaleDateString('sk-SK')}</span>
<button
type="button"
onClick={(e) => {
e.stopPropagation();
removeComment(c);
}}
className="text-gray-300 hover:text-red-600 opacity-0 group-hover:opacity-100 transition-opacity"
title="Zmazať pripomienku"
>
<Trash2 className="w-3.5 h-3.5" />
</button>
</div> </div>
<p className="mt-1 text-xs text-gray-700 whitespace-pre-wrap line-clamp-3"> <p className="mt-1 text-xs text-gray-700 whitespace-pre-wrap line-clamp-3">
{c.text || (c.kind === 'drawing' ? 'Kresba' : '')} {c.text || (c.kind === 'drawing' ? 'Kresba' : '')}
</p> </p>
</button> </div>
); );
})} })}
</div> </div>