import { Suspense } from 'react'; import { prisma } from '@/lib/db'; import { HomePageContent } from './HomePageContent'; import { Photo } from '@prisma/client'; import { serializePhotos, serializePeople, serializeTags } from '@/lib/serialize'; // Force dynamic rendering to prevent database queries during build export const dynamic = 'force-dynamic'; async function getAllPeople() { try { return await prisma.person.findMany({ select: { id: true, first_name: true, last_name: true, middle_name: true, maiden_name: true, date_of_birth: true, created_date: true, }, orderBy: [ { first_name: 'asc' }, { last_name: 'asc' }, ], }); } catch (error: any) { // Handle corrupted data errors (P2023) if (error?.code === 'P2023' || error?.message?.includes('Conversion failed')) { console.warn('Corrupted person data detected, attempting fallback query'); try { // Try with minimal fields first return await prisma.person.findMany({ select: { id: true, first_name: true, last_name: true, // Exclude potentially corrupted optional fields }, orderBy: [ { first_name: 'asc' }, { last_name: 'asc' }, ], }); } catch (fallbackError: any) { console.error('Fallback person query also failed:', fallbackError); // Return empty array as last resort to prevent page crash return []; } } // Re-throw if it's a different error throw error; } } async function getAllTags() { try { return await prisma.tag.findMany({ select: { id: true, tag_name: true, created_date: true, }, orderBy: { tag_name: 'asc' }, }); } catch (error: any) { // Handle corrupted data errors (P2023) if (error?.code === 'P2023' || error?.message?.includes('Conversion failed')) { console.warn('Corrupted tag data detected, attempting fallback query'); try { // Try with minimal fields return await prisma.tag.findMany({ select: { id: true, tag_name: true, // Exclude potentially corrupted date field }, orderBy: { tag_name: 'asc' }, }); } catch (fallbackError: any) { console.error('Fallback tag query also failed:', fallbackError); // Return empty array as last resort to prevent page crash return []; } } // Re-throw if it's a different error throw error; } } export default async function HomePage() { // Fetch photos from database // Note: Make sure DATABASE_URL is set in .env file let photos: any[] = []; // Using any to handle select-based query return type let error: string | null = null; try { // Fetch first page of photos (30 photos) for initial load // Infinite scroll will load more as user scrolls // Try to load with date fields first, fallback if corrupted data exists let photosBase; try { // Use raw query to read dates as strings and convert manually to avoid Prisma conversion issues const photosRaw = await prisma.$queryRaw>` SELECT id, path, filename, date_added, date_taken, processed, media_type FROM photos WHERE processed = true ORDER BY date_taken DESC, id DESC LIMIT 30 `; photosBase = photosRaw.map(photo => ({ id: photo.id, path: photo.path, filename: photo.filename, date_added: new Date(photo.date_added), date_taken: photo.date_taken ? new Date(photo.date_taken) : null, processed: photo.processed, media_type: photo.media_type, })); } catch (dateError: any) { // If date fields are corrupted, load without them and use fallback values // Check for P2023 error code or various date conversion error messages const isDateError = dateError?.code === 'P2023' || dateError?.message?.includes('Conversion failed') || dateError?.message?.includes('Inconsistent column data') || dateError?.message?.includes('Could not convert value'); if (isDateError) { console.warn('Corrupted date data detected, loading photos without date fields'); photosBase = await prisma.photo.findMany({ where: { processed: true }, select: { id: true, path: true, filename: true, processed: true, media_type: true, // Exclude date fields due to corruption }, orderBy: { id: 'desc' }, take: 30, }); // Add fallback date values photosBase = photosBase.map(photo => ({ ...photo, date_added: new Date(), date_taken: null, })); } else { throw dateError; } } // If base query works, load faces separately const photoIds = photosBase.map(p => p.id); const faces = await prisma.face.findMany({ where: { photo_id: { in: photoIds } }, select: { id: true, photo_id: true, person_id: true, location: true, confidence: true, quality_score: true, is_primary_encoding: true, detector_backend: true, model_name: true, face_confidence: true, exif_orientation: true, pose_mode: true, yaw_angle: true, pitch_angle: true, roll_angle: true, landmarks: true, identified_by_user_id: true, excluded: true, Person: { select: { id: true, first_name: true, last_name: true, middle_name: true, maiden_name: true, date_of_birth: true, created_date: true, }, }, // Exclude encoding field (Bytes) to avoid P2023 conversion errors }, }); // Combine the data manually photos = photosBase.map(photo => ({ ...photo, Face: faces.filter(face => face.photo_id === photo.id), })) as any; } catch (err) { error = err instanceof Error ? err.message : 'Failed to load photos'; console.error('Error loading photos:', err); } // Fetch people and tags for search const [people, tags] = await Promise.all([ getAllPeople(), getAllTags(), ]); return (
{error ? (

Error loading photos

{error}

Make sure DATABASE_URL is configured in your .env file

) : (

Loading...

}>
)}
); }