Files
ai-job-search-app/src/app/resumes/page.tsx

151 lines
8.5 KiB
TypeScript

import { prisma } from "@/lib/db";
import Link from "next/link";
export const dynamic = "force-dynamic";
export default async function ResumesPage() {
const resumes = await prisma.resume.findMany({
orderBy: { updatedAt: "desc" },
include: { job: { select: { id: true, title: true, company: true } } },
});
return (
<div className="space-y-6">
{/* Header */}
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 pb-2 border-b border-zinc-200/70 dark:border-zinc-800/70">
<div>
<div className="flex items-center gap-3">
<h1 className="text-2xl sm:text-3xl font-extrabold tracking-tight text-zinc-900 dark:text-white">
Resumes
</h1>
<span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-semibold bg-purple-50 text-purple-700 dark:bg-purple-950/70 dark:text-purple-300 border border-purple-200/60 dark:border-purple-800/60">
{resumes.length} {resumes.length === 1 ? "version" : "versions"}
</span>
</div>
<p className="text-sm text-zinc-500 dark:text-zinc-400 mt-1">
Tailored resumes customized by AI for specific positions and target roles.
</p>
</div>
<Link
href="/jobs"
className="inline-flex items-center gap-1.5 px-4 py-2 rounded-xl text-xs font-semibold text-zinc-700 dark:text-zinc-200 bg-white dark:bg-zinc-900 border border-zinc-200/90 dark:border-zinc-800 hover:bg-zinc-50 dark:hover:bg-zinc-800/70 shadow-2xs transition-all shrink-0"
>
<svg className="w-4 h-4 text-zinc-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" />
</svg>
<span>Browse Jobs Pipeline</span>
</Link>
</div>
{/* Resumes Grid / Empty State */}
{resumes.length === 0 ? (
<div className="rounded-2xl border border-zinc-200/80 dark:border-zinc-800/80 bg-white dark:bg-zinc-900 p-12 text-center shadow-2xs">
<div className="mx-auto flex h-12 w-12 items-center justify-center rounded-2xl bg-purple-50 dark:bg-purple-950/60 text-purple-600 dark:text-purple-400 mb-3">
<svg className="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
<path strokeLinecap="round" strokeLinejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z" />
</svg>
</div>
<h3 className="text-base font-bold text-zinc-900 dark:text-zinc-100">No tailored resumes yet</h3>
<p className="text-xs text-zinc-500 dark:text-zinc-400 mt-1 max-w-sm mx-auto">
Open any job in your tracker and click <strong>“AI Tailor Resume”</strong> to generate a custom CV version optimized for that role.
</p>
<div className="mt-5">
<Link
href="/jobs"
className="inline-flex items-center gap-1.5 px-4 py-2 rounded-xl text-xs font-semibold text-white bg-gradient-to-r from-indigo-600 via-indigo-600 to-violet-600 hover:from-indigo-500 hover:via-indigo-500 hover:to-violet-500 shadow-sm shadow-indigo-500/20 active:scale-95 transition-all"
>
Go to Jobs Pipeline
</Link>
</div>
</div>
) : (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5">
{resumes.map((r) => (
<div
key={r.id}
className="relative flex flex-col justify-between rounded-2xl border border-zinc-200/80 dark:border-zinc-800/80 bg-white dark:bg-zinc-900 p-5 shadow-2xs hover:shadow-md hover:border-zinc-300 dark:hover:border-zinc-700 transition-all duration-200 group"
>
<div>
{/* Stylized Document Thumbnail Placeholder */}
<div className="mb-4 rounded-xl border border-zinc-200/70 dark:border-zinc-800 bg-zinc-50/80 dark:bg-zinc-950/60 p-3.5 space-y-2 group-hover:border-indigo-300/80 dark:group-hover:border-indigo-800/60 transition-colors">
{/* Header bar simulations */}
<div className="flex items-center justify-between">
<div className="h-2 w-2/5 rounded-xs bg-zinc-400 dark:bg-zinc-600" />
<div className="h-1.5 w-1/5 rounded-xs bg-zinc-300 dark:bg-zinc-700" />
</div>
<div className="h-1.5 w-3/5 rounded-xs bg-zinc-300 dark:bg-zinc-700" />
<div className="border-t border-zinc-200 dark:border-zinc-800 pt-1.5 space-y-1.5">
{/* Section 1 */}
<div className="h-1.5 w-1/4 rounded-xs bg-indigo-400/80 dark:bg-indigo-500/80" />
<div className="h-1.5 w-full rounded-xs bg-zinc-200 dark:bg-zinc-800" />
<div className="h-1.5 w-4/5 rounded-xs bg-zinc-200 dark:bg-zinc-800" />
</div>
<div className="pt-0.5 space-y-1.5">
{/* Section 2 */}
<div className="h-1.5 w-1/4 rounded-xs bg-purple-400/80 dark:bg-purple-500/80" />
<div className="h-1.5 w-full rounded-xs bg-zinc-200 dark:bg-zinc-800" />
<div className="h-1.5 w-3/5 rounded-xs bg-zinc-200 dark:bg-zinc-800" />
</div>
</div>
{/* Resume Label & Version Tag */}
<div className="flex items-start justify-between gap-2">
<Link
href={`/resumes/${r.id}`}
className="font-bold text-sm text-zinc-900 dark:text-zinc-100 group-hover:text-indigo-600 dark:group-hover:text-indigo-400 transition-colors line-clamp-1 block flex-1"
>
{r.name}
</Link>
<span className="inline-flex items-center px-2 py-0.5 rounded-md text-[10px] font-semibold bg-purple-50 text-purple-700 dark:bg-purple-950/70 dark:text-purple-300 border border-purple-200/60 dark:border-purple-900/60 capitalize shrink-0">
{r.kind} · v{r.version}
</span>
</div>
{/* Linked Job Title + Company */}
<div className="mt-2.5 text-xs text-zinc-600 dark:text-zinc-400 min-h-[36px]">
{r.job ? (
<div className="line-clamp-2">
<span className="text-zinc-400 dark:text-zinc-500">Target Role: </span>
<Link
href={`/jobs/${r.job.id}`}
className="font-semibold text-zinc-800 dark:text-zinc-200 hover:text-indigo-600 dark:hover:text-indigo-400 transition-colors"
>
{r.job.company} — {r.job.title}
</Link>
</div>
) : (
<span className="text-zinc-400 dark:text-zinc-500 italic">General master resume</span>
)}
</div>
</div>
{/* Bottom Row: Timestamp + Open Button */}
<div className="mt-4 pt-3.5 border-t border-zinc-100 dark:border-zinc-800/80 flex items-center justify-between text-xs">
<span className="text-zinc-400 dark:text-zinc-500 text-[11px]">
{new Date(r.updatedAt).toLocaleDateString("en-US", {
month: "short",
day: "numeric",
year: "numeric",
})}
</span>
<Link
href={`/resumes/${r.id}`}
className="inline-flex items-center gap-1 px-3 py-1.5 rounded-xl font-semibold text-xs text-white bg-indigo-600 hover:bg-indigo-500 shadow-2xs active:scale-95 transition-all group-hover:shadow-indigo-500/20 group-hover:shadow-sm"
>
<span>Open</span>
<svg className="w-3 h-3 group-hover:translate-x-0.5 transition-transform" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2.2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M8.25 4.5l7.5 7.5-7.5 7.5" />
</svg>
</Link>
</div>
</div>
))}
</div>
)}
</div>
);
}