'use client'; import { useState, useEffect } from 'react'; import Link from 'next/link'; import { Image as ImageIcon, Search, Filter, Star, Bookmark, HardDrive } from 'lucide-react'; import { Card, CardContent } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import PhotoViewer from '@/components/photo-viewer'; interface Photo { id: number; path: string; title: string; size: number; thumbnail: string; type: string; bookmark_count: number; avg_rating: number; star_count: number; } export default function PhotosPage() { const [photos, setPhotos] = useState([]); const [loading, setLoading] = useState(true); const [searchTerm, setSearchTerm] = useState(''); const [selectedPhoto, setSelectedPhoto] = useState(null); const [currentPhotoIndex, setCurrentPhotoIndex] = useState(0); const [isViewerOpen, setIsViewerOpen] = useState(false); useEffect(() => { fetchPhotos(); }, []); const fetchPhotos = async () => { try { const response = await fetch('/api/photos'); const data = await response.json(); setPhotos(data); } catch (error) { console.error('Error fetching photos:', error); } finally { setLoading(false); } }; const formatFileSize = (bytes: number) => { if (bytes === 0) return '0 Bytes'; const k = 1024; const sizes = ['Bytes', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; }; const filteredPhotos = photos.filter(photo => photo.title.toLowerCase().includes(searchTerm.toLowerCase()) || photo.path.toLowerCase().includes(searchTerm.toLowerCase()) ); const handlePhotoClick = (photo: Photo, index: number) => { setSelectedPhoto(photo); setCurrentPhotoIndex(index); setIsViewerOpen(true); }; const handleCloseViewer = () => { setIsViewerOpen(false); setSelectedPhoto(null); }; const handleNextPhoto = () => { if (filteredPhotos.length > 0) { const nextIndex = (currentPhotoIndex + 1) % filteredPhotos.length; setCurrentPhotoIndex(nextIndex); setSelectedPhoto(filteredPhotos[nextIndex]); } }; const handlePrevPhoto = () => { if (filteredPhotos.length > 0) { const prevIndex = (currentPhotoIndex - 1 + filteredPhotos.length) % filteredPhotos.length; setCurrentPhotoIndex(prevIndex); setSelectedPhoto(filteredPhotos[prevIndex]); } }; const handleBookmark = async (photoId: number) => { try { await fetch(`/api/bookmarks/${photoId}`, { method: 'POST' }); fetchPhotos(); } catch (error) { console.error('Error bookmarking photo:', error); } }; const handleUnbookmark = async (photoId: number) => { try { await fetch(`/api/bookmarks/${photoId}`, { method: 'DELETE' }); fetchPhotos(); } catch (error) { console.error('Error unbookmarking photo:', error); } }; const handleRate = async (photoId: number, rating: number) => { try { await fetch(`/api/stars/${photoId}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ rating }) }); fetchPhotos(); } catch (error) { console.error('Error rating photo:', error); } }; if (loading) { return (

Loading photos...

); } return ( <>
{/* Header */}

Photos

{photos.length} {photos.length === 1 ? 'photo' : 'photos'} in your library

{/* Search and Filter Bar */}
setSearchTerm(e.target.value)} className="pl-10 bg-background border-border" />
{/* Photos Grid */} {filteredPhotos.length > 0 ? (
{filteredPhotos.map((photo, index) => ( handlePhotoClick(photo, index)} >
{photo.title} { (e.target as HTMLImageElement).src = '/placeholder-photo.svg'; }} />
{/* Photo Type Badge */}
{/* Bookmark and Rating Overlay */}
{/* Rating Stars */} {photo.avg_rating > 0 && (
{[...Array(5)].map((_, i) => ( ))}
)}

{photo.title}

{formatFileSize(photo.size)}

{photo.path}

))}
) : searchTerm ? (

No photos found

Try adjusting your search terms

) : (

No Photos Found

Add media libraries and scan for photos to get started

)}
{/* Photo Viewer */} 1} showBookmarks={true} showRatings={true} formatFileSize={formatFileSize} onBookmark={handleBookmark} onUnbookmark={handleUnbookmark} onRate={handleRate} /> ); }