Improve note deletion UX with double-click confirmation
- Replaced confusing browser confirm() dialog with double-click to delete - First click highlights delete button in red (confirmation state) - Second click within 3 seconds actually deletes the note - Visual feedback with red background on confirmation state - Tooltip changes to 'Click again to confirm deletion' - Removed debug logging from delete handlers - Much clearer and more intuitive deletion flow
This commit is contained in:
12
src/App.tsx
12
src/App.tsx
@@ -147,20 +147,10 @@ function App() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteNote = async (note: Note) => {
|
const handleDeleteNote = async (note: Note) => {
|
||||||
console.log('handleDeleteNote called for note:', note.id, note.title);
|
if (!api) return;
|
||||||
if (!api) {
|
|
||||||
console.log('No API instance');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const confirmed = confirm(`Delete "${note.title}"?`);
|
|
||||||
console.log('User confirmed deletion:', confirmed);
|
|
||||||
if (!confirmed) return;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log('Calling API deleteNote...');
|
|
||||||
await api.deleteNote(note.id);
|
await api.deleteNote(note.id);
|
||||||
console.log('Note deleted successfully, updating state...');
|
|
||||||
setNotes(notes.filter(n => n.id !== note.id));
|
setNotes(notes.filter(n => n.id !== note.id));
|
||||||
if (selectedNoteId === note.id) {
|
if (selectedNoteId === note.id) {
|
||||||
setSelectedNoteId(notes[0]?.id || null);
|
setSelectedNoteId(notes[0]?.id || null);
|
||||||
|
|||||||
@@ -35,12 +35,28 @@ export function NotesList({
|
|||||||
onToggleFavorites,
|
onToggleFavorites,
|
||||||
}: NotesListProps) {
|
}: NotesListProps) {
|
||||||
const [isSyncing, setIsSyncing] = React.useState(false);
|
const [isSyncing, setIsSyncing] = React.useState(false);
|
||||||
|
const [deleteClickedId, setDeleteClickedId] = React.useState<number | null>(null);
|
||||||
|
|
||||||
const handleSync = async () => {
|
const handleSync = async () => {
|
||||||
setIsSyncing(true);
|
setIsSyncing(true);
|
||||||
await onSync();
|
await onSync();
|
||||||
setTimeout(() => setIsSyncing(false), 500);
|
setTimeout(() => setIsSyncing(false), 500);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleDeleteClick = (note: Note, e: React.MouseEvent) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
if (deleteClickedId === note.id) {
|
||||||
|
// Second click - actually delete
|
||||||
|
onDeleteNote(note);
|
||||||
|
setDeleteClickedId(null);
|
||||||
|
} else {
|
||||||
|
// First click - show confirmation state
|
||||||
|
setDeleteClickedId(note.id);
|
||||||
|
// Reset after 3 seconds
|
||||||
|
setTimeout(() => setDeleteClickedId(null), 3000);
|
||||||
|
}
|
||||||
|
};
|
||||||
const formatDate = (timestamp: number) => {
|
const formatDate = (timestamp: number) => {
|
||||||
const date = new Date(timestamp * 1000);
|
const date = new Date(timestamp * 1000);
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
@@ -145,14 +161,13 @@ export function NotesList({
|
|||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={(e) => {
|
onClick={(e) => handleDeleteClick(note, e)}
|
||||||
console.log('Delete button clicked for note:', note.id);
|
className={`ml-2 p-1 rounded transition-all opacity-0 group-hover:opacity-100 ${
|
||||||
e.stopPropagation();
|
deleteClickedId === note.id
|
||||||
console.log('Calling onDeleteNote...');
|
? 'bg-red-600 text-white'
|
||||||
onDeleteNote(note);
|
: 'hover:bg-red-100 dark:hover:bg-red-900/30 text-red-600 dark:text-red-400'
|
||||||
}}
|
}`}
|
||||||
className="ml-2 p-1 hover:bg-red-100 dark:hover:bg-red-900/30 rounded text-red-600 dark:text-red-400 opacity-0 group-hover:opacity-100 transition-opacity"
|
title={deleteClickedId === note.id ? "Click again to confirm deletion" : "Delete"}
|
||||||
title="Delete"
|
|
||||||
>
|
>
|
||||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
|
||||||
|
|||||||
Reference in New Issue
Block a user