added individual entry delete option
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useAuth } from '../contexts/AuthContext'
|
||||
import { getUserEntries, type JournalEntry } from '../lib/api'
|
||||
import { getUserEntries, deleteEntry, type JournalEntry } from '../lib/api'
|
||||
import { decryptEntry } from '../lib/crypto'
|
||||
import { formatIST, getISTDateComponents } from '../lib/timezone'
|
||||
import BottomNav from '../components/BottomNav'
|
||||
@@ -19,6 +19,8 @@ export default function HistoryPage() {
|
||||
const [entries, setEntries] = useState<DecryptedEntry[]>([])
|
||||
const [loadingEntries, setLoadingEntries] = useState(false)
|
||||
const [selectedEntry, setSelectedEntry] = useState<DecryptedEntry | null>(null)
|
||||
const [entryToDelete, setEntryToDelete] = useState<DecryptedEntry | null>(null)
|
||||
const [deleting, setDeleting] = useState(false)
|
||||
|
||||
const { continueTourOnHistory } = useOnboardingTour()
|
||||
|
||||
@@ -175,6 +177,22 @@ export default function HistoryPage() {
|
||||
setSelectedDate(new Date(currentMonth.getFullYear(), currentMonth.getMonth(), day))
|
||||
}
|
||||
|
||||
const handleDeleteConfirm = async () => {
|
||||
if (!entryToDelete || !user || !userId) return
|
||||
setDeleting(true)
|
||||
try {
|
||||
const token = await user.getIdToken()
|
||||
await deleteEntry(userId, entryToDelete.id, token)
|
||||
setEntries((prev) => prev.filter((e) => e.id !== entryToDelete.id))
|
||||
if (selectedEntry?.id === entryToDelete.id) setSelectedEntry(null)
|
||||
} catch (error) {
|
||||
console.error('Failed to delete entry:', error)
|
||||
} finally {
|
||||
setDeleting(false)
|
||||
setEntryToDelete(null)
|
||||
}
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="history-page" style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
||||
@@ -267,21 +285,38 @@ export default function HistoryPage() {
|
||||
</p>
|
||||
) : (
|
||||
selectedDateEntries.map((entry) => (
|
||||
<button
|
||||
<div
|
||||
key={entry.id}
|
||||
type="button"
|
||||
className="entry-card"
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={() => setSelectedEntry(entry)}
|
||||
onKeyDown={(e) => e.key === 'Enter' && setSelectedEntry(entry)}
|
||||
>
|
||||
<div className="entry-header">
|
||||
<span className="entry-date">{formatDate(entry.createdAt)}</span>
|
||||
<span className="entry-time">{formatTime(entry.createdAt)}</span>
|
||||
<div className="entry-header-right">
|
||||
<span className="entry-time">{formatTime(entry.createdAt)}</span>
|
||||
<button
|
||||
type="button"
|
||||
className="entry-delete-btn"
|
||||
title="Delete entry"
|
||||
onClick={(e) => { e.stopPropagation(); setEntryToDelete(entry) }}
|
||||
>
|
||||
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<polyline points="3 6 5 6 21 6" />
|
||||
<path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" />
|
||||
<path d="M10 11v6M14 11v6" />
|
||||
<path d="M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<h4 className="entry-title">{entry.decryptedTitle || entry.title || '[Untitled]'}</h4>
|
||||
{entry.decryptedContent && (
|
||||
<p className="entry-preview">{entry.decryptedContent}</p>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
@@ -352,6 +387,49 @@ export default function HistoryPage() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Delete Confirmation Modal */}
|
||||
{entryToDelete && (
|
||||
<div
|
||||
className="entry-modal-overlay"
|
||||
onClick={(e) => {
|
||||
if (e.target === e.currentTarget && !deleting) setEntryToDelete(null)
|
||||
}}
|
||||
>
|
||||
<div className="entry-modal delete-confirm-modal">
|
||||
<div className="delete-confirm-icon">
|
||||
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<polyline points="3 6 5 6 21 6" />
|
||||
<path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" />
|
||||
<path d="M10 11v6M14 11v6" />
|
||||
<path d="M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2" />
|
||||
</svg>
|
||||
</div>
|
||||
<h2 className="delete-confirm-title">Delete entry?</h2>
|
||||
<p className="delete-confirm-body">
|
||||
"{entryToDelete.decryptedTitle || entryToDelete.title || 'Untitled'}" will be permanently deleted and cannot be recovered.
|
||||
</p>
|
||||
<div className="delete-confirm-actions">
|
||||
<button
|
||||
type="button"
|
||||
className="delete-confirm-cancel"
|
||||
onClick={() => setEntryToDelete(null)}
|
||||
disabled={deleting}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="delete-confirm-delete"
|
||||
onClick={handleDeleteConfirm}
|
||||
disabled={deleting}
|
||||
>
|
||||
{deleting ? 'Deleting…' : 'Delete'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<BottomNav />
|
||||
</div>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user