import { createFileRoute } from "@tanstack/react-router"
import { useState } from "react"
import { useTranslation } from "react-i18next"
import { Calendar, ChevronDown, ExternalLink, Film, Globe, MapPin, User } from "lucide-react"
import { BackButton } from "@/components/back-button"
import { MovieCard } from "@/components/movie-card"
import { EmptyState } from "@/components/empty-state"
import { SwipeTabs } from "@/components/swipe-tabs"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Separator } from "@/components/ui/separator"
import { Skeleton } from "@/components/ui/skeleton"
import { tmdbProfileUrl } from "@/lib/api/client"
import { usePersonCredits } from "@/hooks/use-search"
import { useDocumentTitle } from "@/hooks/use-document-title"
import { shortDate } from "@/lib/date"
import { differenceInYears, parseISO } from "date-fns"
export const Route = createFileRoute("/_app/people/$id")({
component: PersonDetailPage,
})
function PersonDetailPage() {
const { t } = useTranslation()
const { id } = Route.useParams()
const { data, isPending } = usePersonCredits(id)
useDocumentTitle(data?.person.name)
if (isPending) return
if (!data) return null
const { person, cast, crew } = data
const age = person.birthday
? differenceInYears(
person.deathday ? parseISO(person.deathday) : new Date(),
parseISO(person.birthday),
)
: null
const creditTabs = [
...(cast.length > 0 ? [{ value: "cast", label: t("movie.cast") + ` (${cast.length})` }] : []),
...(crew.length > 0 ? [{ value: "crew", label: t("movie.crew") + ` (${crew.length})` }] : []),
] as const
return (
{/* Header */}
{person.profile_path ? (
})
) : (
)}
{person.name}
{person.known_for_department && (
{person.known_for_department}
)}
{(person.homepage || person.imdb_url) && (
)}
{/* Details card */}
{(person.birthday || person.place_of_birth) && (
{person.birthday && (
{shortDate(person.birthday)}
{age != null && (
({age})
)}
)}
{person.deathday && (
{shortDate(person.deathday)}
({t("person.deathday").toLowerCase()})
)}
{person.place_of_birth && (
{person.place_of_birth}
)}
)}
{/* Biography */}
{person.biography &&
}
{/* Also known as */}
{person.also_known_as?.length > 0 && (
{t("person.alsoKnownAs")}
{person.also_known_as.map((name) => (
{name}
))}
)}
{/* Credits */}
{creditTabs.length > 0 ? (
{(tab) => (
<>
{tab === "cast" && (
{cast.map((c) => (
))}
)}
{tab === "crew" && (
{crew.map((c) => (
))}
)}
>
)}
) : (
)}
)
}
const BIO_COLLAPSE_THRESHOLD = 300
function BiographySection({ text }: { text: string }) {
const { t } = useTranslation()
const isLong = text.length > BIO_COLLAPSE_THRESHOLD
const [expanded, setExpanded] = useState(!isLong)
return (
{t("person.biography")}
{text}
{isLong && (
)}
)
}
function PersonSkeleton() {
return (
{[1, 2, 3, 4].map((i) => (
))}
)
}