import { useEffect, useMemo, useState } from 'react'; import { useAI, share } from '@deplixo/sdk'; import { PetGrid } from './components/PetGrid.jsx'; import { Favorites } from './components/Favorites.jsx'; import { AddPetForm } from './components/AddPetForm.jsx'; function App() { const { generate, loading: aiLoading, error: aiError } = useAI(); const [activeTab, setActiveTab] = useState('browse'); const [showAddForm, setShowAddForm] = useState(false); const [lifestyle, setLifestyle] = useState(''); const [livingSituation, setLivingSituation] = useState(''); const [recommendedPets, setRecommendedPets] = useState([]); const [matchSummary, setMatchSummary] = useState(''); const [matchError, setMatchError] = useState(''); const [shareMessage, setShareMessage] = useState(''); const [shareError, setShareError] = useState(''); const [selectedPetId, setSelectedPetId] = useState(''); const tabs = [ { id: 'browse', label: '🐾 Browse Pets', icon: '🏠' }, { id: 'favorites', label: '💕 Favorites', icon: '💕' }, { id: 'manage', label: '🏥 Manage Listings', icon: '🏥' } ]; const getPetProfileUrl = petId => { const url = new URL(window.location.href); url.searchParams.set('pet', petId); return url.toString(); }; const copyShareLink = async pet => { setShareMessage(''); setShareError(''); const shareUrl = getPetProfileUrl(pet.id); const shareText = `Check out ${pet.name} on PawFinder: ${shareUrl}`; try { if (navigator.share) { await navigator.share({ title: `${pet.name} | PawFinder`, text: shareText, url: shareUrl }); setShareMessage('Share sheet opened for this pet profile.'); return; } if (navigator.clipboard?.writeText) { await navigator.clipboard.writeText(shareUrl); setShareMessage('Share link copied to clipboard.'); return; } setShareError('Sharing is not available in this browser.'); } catch (error) { setShareError('Could not copy or share the link right now.'); } }; const handleOpenSharedPet = async petId => { setSelectedPetId(petId); setActiveTab('browse'); window.history.replaceState({}, '', getPetProfileUrl(petId)); try { const element = document.getElementById(`pet-card-${petId}`); if (element) { element.scrollIntoView({ behavior: 'smooth', block: 'center' }); } } catch { // no-op } }; useEffect(() => { const syncFromUrl = () => { const url = new URL(window.location.href); const petId = url.searchParams.get('pet') || ''; if (petId) { setSelectedPetId(petId); setActiveTab('browse'); } }; syncFromUrl(); window.addEventListener('popstate', syncFromUrl); return () => window.removeEventListener('popstate', syncFromUrl); }, []); const handleMatchPets = async () => { setMatchError(''); setMatchSummary(''); try { const response = await fetch('/api/pets'); const allPets = await response.json(); const promptPets = allPets.map((pet, index) => ({ index, id: pet.id, name: pet.name, species: pet.species, breed: pet.breed, age: pet.age, temperament: pet.temperament, description: pet.description, adoptionFee: pet.adoptionFee, size: pet.size, energyLevel: pet.energyLevel, goodWithKids: pet.goodWithKids, goodWithPets: pet.goodWithPets, apartmentFriendly: pet.apartmentFriendly })); const result = await generate({ system: 'You are an adoption matchmaking assistant. Score pets from 0-100 based on how well they fit the adopter lifestyle and living situation. Return JSON only with this shape: {"summary":"string","recommendations":[{"id":"pet-id","score":0,"reason":"string"}]}. Only recommend pets from the provided list. Prefer concise reasons and sort recommendations highest score first.', user: JSON.stringify({ adopterProfile: { lifestyle, livingSituation }, pets: promptPets }), json: true }); const recommendations = Array.isArray(result?.recommendations) ? result.recommendations : []; const sortedIds = recommendations .filter(item => item && item.id) .sort((a, b) => (b.score ?? 0) - (a.score ?? 0)) .map(item => item.id); const petsById = new Map(allPets.map(pet => [pet.id, pet])); const matched = sortedIds .map(id => petsById.get(id)) .filter(Boolean); setRecommendedPets(matched); setMatchSummary(result?.summary || 'Here are pets that look like a good fit based on your preferences.'); } catch (error) { setMatchError('Unable to load pets for matching right now.'); } }; const profileBanner = useMemo(() => { if (!selectedPetId) return null; return `Open pet profile: ${selectedPetId}`; }, [selectedPetId]); return (

🐾 PawFinder

Find your forever friend

{activeTab === 'browse' && (

AI Matchmaker

Tell us about your lifestyle and living situation, and we will recommend pets that fit best.