'use client' import { useState, useEffect } from 'react' import { useTranslations, useLocale } from 'next-intl' import { useAuth } from '@/hooks/use-auth' import { ProtectedRoute } from '@/components/auth/protected-route' import { useRouter } from 'next/navigation' import { Container, Paper, Box, Typography, Card, CardContent, CardActions, Button, Chip, Divider, Grid, IconButton, Alert, CircularProgress, Tab, Tabs, List, ListItem, ListItemIcon, ListItemText, ListItemSecondary } from '@mui/material' import { Bookmark, BookmarkBorder, MenuBook, Article, Delete, Launch, AccessTime, Note } from '@mui/icons-material' interface BookmarkItem { id: string type: 'chapter' | 'verse' title: string subtitle: string note?: string createdAt: string color?: string text?: string navigation: { bookId: string chapterNum: number verseNum?: number } verse?: { id: string } } interface BookmarkStats { total: number chapters: number verses: number } export default function BookmarksPage() { const { user } = useAuth() const t = useTranslations('bookmarks') const locale = useLocale() const router = useRouter() const [bookmarks, setBookmarks] = useState([]) const [stats, setStats] = useState({ total: 0, chapters: 0, verses: 0 }) const [loading, setLoading] = useState(true) const [error, setError] = useState('') const [activeTab, setActiveTab] = useState(0) const [deletingIds, setDeletingIds] = useState>(new Set()) // Fetch bookmarks useEffect(() => { if (user) { fetchBookmarks() } }, [user]) const fetchBookmarks = async () => { try { setLoading(true) setError('') const token = localStorage.getItem('authToken') if (!token) { setError(t('authRequired')) return } const response = await fetch(`/api/bookmarks/all?locale=${locale}`, { headers: { 'Authorization': `Bearer ${token}` } }) if (response.ok) { const data = await response.json() setBookmarks(data.bookmarks || []) setStats(data.stats || { total: 0, chapters: 0, verses: 0 }) } else { const data = await response.json() setError(data.error || t('loadError')) } } catch (error) { console.error('Error fetching bookmarks:', error) setError(t('loadError')) } finally { setLoading(false) } } const handleNavigateToBookmark = (bookmark: BookmarkItem) => { const params = new URLSearchParams({ book: bookmark.navigation.bookId, chapter: bookmark.navigation.chapterNum.toString() }) if (bookmark.navigation.verseNum) { params.set('verse', bookmark.navigation.verseNum.toString()) } router.push(`/${locale}/bible?${params.toString()}`) } const handleDeleteBookmark = async (bookmark: BookmarkItem) => { if (!user) return setDeletingIds(prev => new Set(prev).add(bookmark.id)) const token = localStorage.getItem('authToken') if (!token) { setDeletingIds(prev => { const newSet = new Set(prev) newSet.delete(bookmark.id) return newSet }) return } try { const endpoint = bookmark.type === 'chapter' ? `/api/bookmarks/chapter?bookId=${bookmark.navigation.bookId}&chapterNum=${bookmark.navigation.chapterNum}&locale=${locale}` : `/api/bookmarks/verse?verseId=${bookmark.verse.id}&locale=${locale}` const response = await fetch(endpoint, { method: 'DELETE', headers: { 'Authorization': `Bearer ${token}` } }) if (response.ok) { // Remove from local state setBookmarks(prev => prev.filter(b => b.id !== bookmark.id)) setStats(prev => ({ total: prev.total - 1, chapters: bookmark.type === 'chapter' ? prev.chapters - 1 : prev.chapters, verses: bookmark.type === 'verse' ? prev.verses - 1 : prev.verses })) } } catch (error) { console.error('Error deleting bookmark:', error) } finally { setDeletingIds(prev => { const newSet = new Set(prev) newSet.delete(bookmark.id) return newSet }) } } const formatDate = (dateString: string) => { const date = new Date(dateString) return date.toLocaleDateString(locale, { year: 'numeric', month: 'short', day: 'numeric' }) } const filteredBookmarks = () => { switch (activeTab) { case 1: return bookmarks.filter(b => b.type === 'chapter') case 2: return bookmarks.filter(b => b.type === 'verse') default: return bookmarks } } if (loading) { return ( ) } return ( {/* Header */} {t('title')} {t('subtitle')} {/* Stats */} {stats.total} {t('totalBookmarks')} {stats.chapters} {t('chapterBookmarks')} {stats.verses} {t('verseBookmarks')} {error && ( {error} )} {/* Filter Tabs */} setActiveTab(newValue)}> } iconPosition="start" /> } iconPosition="start" /> } iconPosition="start" /> {/* Bookmarks List */} {filteredBookmarks().length === 0 ? ( {t('noBookmarks')} {t('noBookmarksDescription')} ) : ( {filteredBookmarks().map((bookmark) => ( {bookmark.type === 'chapter' ? ( ) : (
)} {bookmark.title} {bookmark.subtitle} {bookmark.text && ( "{bookmark.text}" )} {bookmark.note && ( {bookmark.note} )} {formatDate(bookmark.createdAt)} handleDeleteBookmark(bookmark)} disabled={deletingIds.has(bookmark.id)} > {deletingIds.has(bookmark.id) ? ( ) : ( )} ))} )} ) }