159 lines
5.4 KiB
TypeScript
159 lines
5.4 KiB
TypeScript
"use client";
|
|
|
|
import { useNavigate } from "react-router-dom";
|
|
import { motion, AnimatePresence } from "framer-motion";
|
|
import type { SearchResult } from "@/types/search";
|
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
import { Skeleton } from "@/components/ui/skeleton";
|
|
import AnimatedImage from "@/components/ui/animated-image";
|
|
|
|
interface SearchResultsProps {
|
|
results: SearchResult[];
|
|
isLoading: boolean;
|
|
hasSearched?: boolean;
|
|
}
|
|
|
|
export default function SearchResults({
|
|
results,
|
|
isLoading,
|
|
hasSearched = false,
|
|
}: SearchResultsProps) {
|
|
const navigate = useNavigate();
|
|
|
|
// Define animation variants
|
|
const container = {
|
|
hidden: { opacity: 0 },
|
|
show: {
|
|
opacity: 1,
|
|
transition: {
|
|
staggerChildren: 0.1,
|
|
},
|
|
},
|
|
};
|
|
|
|
const item = {
|
|
hidden: { opacity: 0, y: 20 },
|
|
show: { opacity: 1, y: 0, transition: { duration: 0.5 } },
|
|
};
|
|
|
|
if (isLoading) {
|
|
return (
|
|
<div>
|
|
<h3 className="text-2xl font-semibold mb-6 font-serif">
|
|
Search Results
|
|
</h3>
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
{[...Array(6)].map((_, i) => (
|
|
<Card
|
|
key={i}
|
|
className="overflow-hidden border border-gray-200 shadow-none rounded-md bg-white"
|
|
>
|
|
<div className="relative h-48 w-full">
|
|
<Skeleton className="h-full w-full" />
|
|
</div>
|
|
<CardHeader>
|
|
<Skeleton className="h-6 w-3/4 mb-2" />
|
|
<Skeleton className="h-4 w-1/2" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<Skeleton className="h-4 w-full mb-2" />
|
|
<Skeleton className="h-4 w-full mb-2" />
|
|
<Skeleton className="h-4 w-3/4" />
|
|
</CardContent>
|
|
</Card>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (results.length === 0 && hasSearched) {
|
|
return (
|
|
<motion.div
|
|
className="text-center py-12 bg-gray-50 rounded-lg border border-gray-200"
|
|
initial={{ opacity: 0, y: 20 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ duration: 0.5 }}
|
|
>
|
|
<h3 className="text-2xl font-semibold mb-4 font-serif">
|
|
No Results Found
|
|
</h3>
|
|
<p className="text-gray-500">
|
|
Try adjusting your search criteria to find more records.
|
|
</p>
|
|
</motion.div>
|
|
);
|
|
}
|
|
|
|
if (results.length === 0) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<div>
|
|
<h3 className="text-2xl font-semibold mb-6 font-serif">
|
|
Search Results ({results.length})
|
|
</h3>
|
|
<AnimatePresence>
|
|
<motion.div
|
|
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"
|
|
variants={container}
|
|
initial="hidden"
|
|
animate="show"
|
|
>
|
|
{results.map((person) => (
|
|
<motion.div key={person.person_id || person.id_card_no} variants={item} onClick={() => navigate(`/migrants/${person.person_id}`)}>
|
|
<div className="block h-full cursor-pointer">
|
|
<Card className="overflow-hidden hover:shadow-lg transition-shadow h-full border border-gray-200 group">
|
|
<div className="relative h-48 w-full overflow-hidden">
|
|
<AnimatedImage
|
|
src={
|
|
"/placeholder.svg?height=300&width=300"
|
|
}
|
|
alt=""
|
|
fill
|
|
/>
|
|
<div className="absolute inset-0 bg-gradient-to-t from-black/70 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300" />
|
|
<div className="absolute bottom-0 left-0 right-0 p-3 transform translate-y-full group-hover:translate-y-0 transition-transform duration-300">
|
|
<div className="flex space-x-1">
|
|
<div className="h-6 w-2 bg-green-600" />
|
|
<div className="h-6 w-2 bg-white" />
|
|
<div className="h-6 w-2 bg-red-600" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<CardHeader>
|
|
<CardTitle className="font-serif">
|
|
{person.full_name}
|
|
</CardTitle>
|
|
<p className="text-sm text-gray-500">
|
|
{person.migration?.date_of_arrival_nt ?
|
|
`Arrived ${new Date(person.migration.date_of_arrival_nt).getFullYear()}` : 'Date unknown'}
|
|
</p>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="space-y-2">
|
|
<p>
|
|
<span className="font-medium">From:</span>{" "}
|
|
{person.place_of_birth || 'Unknown'}, Italy
|
|
</p>
|
|
<p>
|
|
<span className="font-medium">Settled in:</span>{" "}
|
|
{person.residence?.town_or_city || 'Unknown'}, NT
|
|
</p>
|
|
<p>
|
|
<span className="font-medium">Occupation:</span>{" "}
|
|
{person.occupation || 'Unknown'}
|
|
</p>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
</motion.div>
|
|
))}
|
|
</motion.div>
|
|
</AnimatePresence>
|
|
</div>
|
|
);
|
|
}
|