diff --git a/src/App.css b/src/App.css index 3de0886..54b8f09 100644 --- a/src/App.css +++ b/src/App.css @@ -642,9 +642,9 @@ display: flex; align-items: center; justify-content: center; - width: fit-content; + width: 100%; margin: 0 auto; - padding: 0 1.875rem; + padding: 0.875rem 1.5rem; min-height: 66px; border-radius: 100px; background: #f0fdf4; @@ -653,11 +653,29 @@ font-size: 1.3125rem; font-weight: 600; color: #15803d; - white-space: nowrap; + text-align: center; + white-space: normal; + word-break: break-word; opacity: 0; animation: save-inline-quote-in 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards; } +@media (max-width: 479px) { + .save-inline-quote { + font-size: 1rem; + min-height: 52px; + border-radius: 20px; + } +} + +@media (min-width: 480px) { + .save-inline-quote { + width: fit-content; + white-space: nowrap; + padding: 0 1.875rem; + } +} + @keyframes save-inline-quote-in { 0% { opacity: 0; transform: scale(0.88) translateY(4px); } 100% { opacity: 1; transform: scale(1) translateY(0); } @@ -1098,6 +1116,32 @@ box-shadow: 0 5px 16px rgba(0, 0, 0, 0.09); } +.entry-header-right { + display: flex; + align-items: center; + gap: 0.5rem; +} + +.entry-delete-btn { + display: flex; + align-items: center; + justify-content: center; + width: 1.625rem; + height: 1.625rem; + border-radius: 7px; + border: 1px solid #fee2e2; + background: #fff5f5; + color: #ef4444; + cursor: pointer; + transition: background 0.18s ease, border-color 0.18s ease; + padding: 0; + flex-shrink: 0; +} +.entry-delete-btn:hover { + background: #fee2e2; + border-color: #fca5a5; +} + .entry-header { display: flex; align-items: center; @@ -1775,6 +1819,80 @@ font-family: "Sniglet", system-ui; } +/* Delete confirmation modal */ +.delete-confirm-modal { + text-align: center; + padding: 2rem 1.5rem; +} + +.delete-confirm-icon { + display: flex; + align-items: center; + justify-content: center; + width: 3.5rem; + height: 3.5rem; + border-radius: 50%; + background: #fee2e2; + color: #ef4444; + margin: 0 auto 1rem; +} + +.delete-confirm-title { + margin: 0 0 0.5rem; + font-size: 1.25rem; + color: #111827; + font-family: "Sniglet", system-ui; +} + +.delete-confirm-body { + color: #6b7280; + font-size: 0.9rem; + font-family: "Sniglet", system-ui; + margin: 0 0 1.5rem; + line-height: 1.5; +} + +.delete-confirm-actions { + display: flex; + gap: 0.75rem; + justify-content: center; +} + +.delete-confirm-cancel, +.delete-confirm-delete { + flex: 1; + max-width: 10rem; + padding: 0.625rem 1rem; + border-radius: 12px; + font-size: 0.9375rem; + font-family: "Sniglet", system-ui; + cursor: pointer; + transition: all 0.18s ease; + border: none; +} + +.delete-confirm-cancel { + background: #f3f4f6; + color: #374151; +} +.delete-confirm-cancel:hover:not(:disabled) { + background: #e5e7eb; +} + +.delete-confirm-delete { + background: #ef4444; + color: #fff; +} +.delete-confirm-delete:hover:not(:disabled) { + background: #dc2626; +} + +.delete-confirm-cancel:disabled, +.delete-confirm-delete:disabled { + opacity: 0.6; + cursor: not-allowed; +} + /* ---- Responsive: tablet+ (≥ 768px) ---- */ @media (min-width: 768px) { .entry-modal-overlay { @@ -2449,6 +2567,33 @@ color: #f87171; } +[data-theme="dark"] .entry-delete-btn { + background: rgba(239, 68, 68, 0.08); + border-color: rgba(239, 68, 68, 0.2); + color: #f87171; +} +[data-theme="dark"] .entry-delete-btn:hover { + background: rgba(239, 68, 68, 0.18); + border-color: rgba(239, 68, 68, 0.35); +} + +[data-theme="dark"] .delete-confirm-modal { + background: #1a1a1a; +} +[data-theme="dark"] .delete-confirm-title { + color: #e8f5e8; +} +[data-theme="dark"] .delete-confirm-body { + color: #7a8a7a; +} +[data-theme="dark"] .delete-confirm-cancel { + background: #252525; + color: #b0b8b0; +} +[data-theme="dark"] .delete-confirm-cancel:hover:not(:disabled) { + background: #303030; +} + [data-theme="dark"] .entry-modal-overlay { background: rgba(0, 0, 0, 0.7); } diff --git a/src/pages/HistoryPage.tsx b/src/pages/HistoryPage.tsx index 55b87d4..1050785 100644 --- a/src/pages/HistoryPage.tsx +++ b/src/pages/HistoryPage.tsx @@ -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([]) const [loadingEntries, setLoadingEntries] = useState(false) const [selectedEntry, setSelectedEntry] = useState(null) + const [entryToDelete, setEntryToDelete] = useState(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 (
@@ -267,21 +285,38 @@ export default function HistoryPage() {

) : ( selectedDateEntries.map((entry) => ( - +

{entry.decryptedTitle || entry.title || '[Untitled]'}

{entry.decryptedContent && (

{entry.decryptedContent}

)} - + )) )} @@ -352,6 +387,49 @@ export default function HistoryPage() { )} + {/* Delete Confirmation Modal */} + {entryToDelete && ( +
{ + if (e.target === e.currentTarget && !deleting) setEntryToDelete(null) + }} + > +
+
+ + + + + + +
+

Delete entry?

+

+ "{entryToDelete.decryptedTitle || entryToDelete.title || 'Untitled'}" will be permanently deleted and cannot be recovered. +

+
+ + +
+
+
+ )} + )